美文网首页
TypeScript基础语法

TypeScript基础语法

作者: 李永开 | 来源:发表于2023-11-06 17:50 被阅读0次

    一.简介

    TypeScript是JavaScript的超集,增加了数据类型, 帮助JS检查错误, 防止在大型项目中JS出现解释错误.
    TypeScript最后还是会编译成JS.

    二. 类型

    2.1 基本类型

    let message: string = 'hello world 1';
    let b: boolean = true;
    let str: string | null | undefined = "|为联合语法"
    
    //数组
    let arr1: Array<number> = [10, 20 ,30]
    let arr2: number[] = [2, 3, 4]
    let arr3: Array<number | string> = [666, "真的666"]
    //参数展开运算符
    let arr5: number[] = [1, 2, 3]
    let arr6: number[] = [4, 5]
    arr5.push(...arr6)
    console.log(arr5)//[LOG]: [1, 2, 3, 4, 5]
    
    //元组
    let tuple: [number, string] = [666, "这是元组"]
    console.log(message, b, str, arr1, arr2, arr3, tuple);
    
    //函数
    let add = (x: number, y: number):number => x + y
    console.log("合为"+add(1, 2))
    
    //对象
    let obj0: Object;
    let obj: {x: number, y: number} = {x: 1, y: 2}
    console.log("obj的值为" + obj.y)
    
    //symbol 全局唯一引用
    //symbol 类型表示一个独一无二的标识符。每个通过 Symbol 函数创建的 symbol 都是唯一的,即使它们的描述相同。
    let s1: symbol = Symbol()
    let s2 = Symbol()
    // 创建一个唯一的 symbol
    const mySymbol: symbol = Symbol("mySymbol");
    // 创建另一个唯一的 symbol
    const anotherSymbol: symbol = Symbol("mySymbol");
    // 由于每个 symbol 都是唯一的,这两个 symbol 不相等
    console.log(mySymbol === anotherSymbol);  // 输出: false
    
    //undefined
    let un: undefined = undefined;
    let nu: null = null;
    //message = null; //报错,因为启动了strictNullChecks(严格null校验)
    
    //void
    let noReturn = () => {}//let noReturn: () => void
    
    //any, 变量的默认类型为any
    let aaany //let aaany: any
    
    //nerver
    let error = () => {//let error: () => never
        throw new Error("error")
    }
    let endless = () => {//let endless: () => never
        while(true) {
        }
    }
    

    2.2 自定义类型

    
    //let 可变参数
    let aString = "hello"
    aString = "world"
    
    //const 不可变参数
    const bString = "666"
    bString = "777"//报错
    
    //使用let来实现const, 将cString的类型定义为一个'can not changed string'这样一个特殊类型
    //等号前后要保持一致,否则会报错
    let cString: 'can not changed string' = "can not changed string"
    cString = "yes"//报错
    
    //使用特殊类型
    function printText(text: string, aligment: "left" | "right" | "center") {
      console.log(text + "---" + aligment)
    }
    printText("label", "center")//[LOG]: "label---center" 
    
    

    三. 枚举

    //数字枚举
    enum Season {
        Spring,
        Summer,
        Fall,
        Winter
    }
    console.log(Season.Spring)//0
    console.log(Season.Fall)//2
    
    //枚举的原理
    //转化为JS
    /*
    "use strict";
    var Season;
    (function (Season) {
        Season[Season["Spring"] = 0] = "Spring";
        Season[Season["Summer"] = 1] = "Summer";
        Season[Season["Fall"] = 2] = "Fall";
        Season[Season["Winter"] = 3] = "Winter";
    })(Season || (Season = {}));
    console.log(Season.Spring); //0
    console.log(Season.Fall); //2
    */
    
    
    //字符串枚举
    enum Message {
        Successs = "成功",
        Fail = "失败"
    }
    /*
    var Message;
    (function (Message) {
        Message["Successs"] = "\u6210\u529F";
        Message["Fail"] = "\u5931\u8D25";
    })(Message || (Message = {}));
    */
    
    //异构枚举
    enum Anser{
        N,
        Y = "YES"
    }
    /*
    var Anser;
    (function (Anser) {
        Anser[Anser["N"] = 0] = "N";
        Anser["Y"] = "YES";
    })(Anser || (Anser = {}));
    */
    
    
    //枚举成员
    enum Char {
        //const类型, 编译时确定值
        a,          //未定义
        b = Char.a, //对其他枚举的引用
        c = 1 + 3,  //常量
    
        //computed类型, 运行时计算确定值
        d = Math.random(),
        e = "123".length
    }
    /*
    var Char;
    (function (Char) {
        //const类型, 编译时确定值
        Char[Char["a"] = 0] = "a";
        Char[Char["b"] = 0] = "b";
        Char[Char["c"] = 4] = "c";
        //computed类型, 运行时计算确定值
        Char[Char["d"] = Math.random()] = "d";
        Char[Char["e"] = "123".length] = "e";
    })(Char || (Char = {}));
    */
    
    //常量枚举, 使用const声明; 不会被编译进代码, 相当于预编译的宏替换
    const enum Month {
        Jan,
        Fri,
        Mar
    }
    
    //枚举类型
    enum E {a, b}
    enum F {a = 1, b = 2}
    enum G {a = "hhh", b = "666"}
    
    //let le: E = 3   //Type '3' is not assignable to type 'E'.
    //let lf: F = 3   //Type '3' is not assignable to type 'F'.
    let lg: G.a = G.a
    

    四.类型接口

    4.1 对象类型接口

    interface list {
        readonly id: number,    //readonly, 只读属性
        name: string,
        age?: number            //?可选参数
    }
    interface list1 {
        readonly id: number,    //readonly, 只读属性
        name: string,
        age?: number            //?可选参数
    }
    //interface也可以继承
    interface list2  extends list, list1{
    }
    
    interface StringArray {
        [index: number]:string
    }
    let chars: StringArray = ["A", "B", "C"]
    console.log(chars[2])//C
    
    interface Names {
        [x: string]:string | undefined,
        [index: number]:string
    }
    let names: Names = {
        0: "A",
        1: "B",
        "2": "C",
        "Wow": "真的6啊"
    }
    console.log(names[1], names["Wow"])//"B",  "真的6啊" 
    

    4.2 函数类型接口

    //普通函数变量, 不能被继承
    let add0: (x: number, y: number) => number; //add0是一个函数类型的变量
    add0 = function(x, y) {                     //给变量复制真正的函数体
        return x + y
    }
    console.log(add0(1, 2))// 3
    
    //函数类型接口
    interface Add1 {
        (x: number, y: number): number
    }
    let add1: Add1 = function (x, y){
        return x + y
    }
    console.log(add1(1, 5))//6
    
    // 搞个别名
    type Add2 = (x: number, y: number) => number
    let add2: Add2 = (x, y) => x + y
    console.log(add2(1, 9))//10
    
    //可选参数, z可以不传, 且必须位于必选参数之后
    function add5(x: number, y: number, defaultValue=6, z?: number) {
        return z ? x + y + defaultValue + z : x + y + defaultValue;
    }
    console.log(add5(1, 2), add5(1, 2, 3))//[LOG]: 9,  6 
    

    五.类

    
    //抽象类, 不能被实例化, 只能被继承
    abstract class Animal {
        eat() {
            console.log("eat")
        }
    }
    
    
    class Dog extends Animal{
        name: string
        static food: string = "骨头"//类成员,使用类名调用
        constructor(name: string) {
            super()
            this.name = name
        }
        run() {
    
        }
    }
    console.log(Dog.prototype)
    
    let d = new Dog("汪汪汪")
    d.eat();
    console.log(d, d.name)
    /*
    [LOG]: Dog: {
      "name": "汪汪汪"
    },  "汪汪汪" 
     */
    
    
    //哈士奇继承自Dog
    class Husky extends Dog {
        color: string
        constructor(name: string, color: string) {
            super(name)
            this.color = color
        }
    }
    
    //哈士奇继承自Dog-> 给参数增加public属性,可以不用在类里面定义color: string了
    class Husky1 extends Dog {
        constructor(name: string, public color: string) {
            super(name)
            this.color = color
        }
    }
    
    
    //private   也可以使用#变量来实现private
    //protect
    // public
    

    六.类型断言

    • 使用as或者<>来类型断言
    • 类型断言会在运行时被删除
    const m1 = document.getElementById("main") as HTMLCanvasElement
    const m2 = <HTMLCanvasElement>document.getElementById("main")
    

    七.类型缩小

    7.1 使用typeof来实现类型守卫

    let s: string | number = "astring"
    // s = 666
    if (typeof s === "string") {
       console.log("字符串")
    } else if (typeof s === "number") {
         console.log("数字")
    }
    
    let ret: typeof s
    ret = "0.0"
    

    7.2 真值缩小

    function havePeople(count: number | string | null | undefined) {
      if (count) {
        console.log("有人")
      } else {
        console.log("没人")
      }
    }
    //针对number 非0即为true
    havePeople(-1)  //[LOG]: "有人" 
    havePeople(0)   //[LOG]: "没人" 
    havePeople(1)   //[LOG]: "有人" 
    
    //针对string  非空字符串为true
    havePeople("")  //[LOG]: "没人"
    havePeople("h") //[LOG]: "有人"
    
    //null和undefined都为false
    havePeople(null)      //[LOG]: "没人"
    havePeople(undefined) //[LOG]: "没人"
    
    //或者使用一下方法 大写Boolean或者!!, !!其实就是取反再取反
    console.log(Boolean(""))  //false
    console.log(Boolean("h")) //true
    console.log(!!0)          //false
    console.log(!!1)          //true
    

    7.3 等值缩小

    使用== === != !===来实现
    在 TypeScript 中,== 和 === 是用于比较值的操作符,它们的行为与 JavaScript 中的相同。

    • == 是松散相等性比较,也称为“不严格相等”。在比较时,会进行类型转换,尝试使两侧的值类型相同,然后再进行比较。
    • === 是严格相等性比较,也称为“严格相等”。它不进行类型转换,只有在类型和值都相同时才被认为相等。
    let a: number = 5
    let b: string = "5"
    // 使用 ==
    console.log(a == b);  // 输出: true,因为在比较时会进行类型转换
    // 使用 ===
    console.log(a === b);  // 输出: false,因为严格相等要求类型和值都相同
    
    let n1 = 5
    let n2 = 6
    console.log(n1 == n2)//false
    console.log(n1 === n2)//false
    

    7.4 in

    在 TypeScript 中,in 关键字主要用于检查对象是否包含某个属性。它可以用于两个场景:

    • 检查对象是否包含某个属性
    let myObject = { key1: 'value1', key2: 'value2' };
    
    if ('key1' in myObject) {
      console.log('myObject has key1 property');
    } else {
      console.log('myObject does not have key1 property');
    }
    
    • 遍历对象的属性
    let myObject = { key1: 'value1', key2: 'value2' };
    for (let key in myObject) {
      console.log(`Property: ${key}, Value: ${myObject[key]}`);
    }
    //[LOG]: "Property: key1, Value: value1" 
    //[LOG]: "Property: key2, Value: value2" 
    

    八. 函数

    8.1 调用签名

    可以给函数绑定一个属性

    type DescriptionFuntion = {
        description: string
        (arg: number): boolean
    }
    
    function doSomething(fn: DescriptionFuntion) {
      console.log(fn.description + " return" + fn(6))
    }
    
    function fn(n: number) {
      console.log(n)
      return true
    }
    fn.description = "调用签名"
    
    doSomething(fn)
    
    //[LOG]: 6 
    //[LOG]: "调用签名return true" 
    

    8.2 构造签名

    class Cls {
      name: string
      constructor(name: string) {
        this.name = name
      }
    }
    
    //方法1  字面量方式构造签名
    function fn0(cls: new(name: string) => Cls): Cls {
       return new cls("aaa")
    }
    const cls0: Cls = fn0(Cls)
    console.log(cls0)
    
    function fnt<T>(cls: new(name: string) => T): T {
        return new cls("ttt")
    }
    const clst: Cls = fnt(Cls)
    console.log(clst)
    
    //方法2  接口对象字面量方式构造签名
    function fn1(cls: {new (name: string): Cls}, name: string): Cls {
      return new cls(name)
    }
    const cls1: Cls = fn1(Cls, "bbb")
    console.log(cls1)
    
    //方法3 使用type或者interface
    type ClsConstrutor = {
      new (name: string):Cls
    }
    function fn2(cls: ClsConstrutor): Cls {
      return new cls("ccc")
    }
    

    九.泛型

    9.1 类型限制

    //泛型T必须要有一个length属性
    function longest<T extends {length: number}> (a: T, b: T) {
      return a.length > b.length ? a : b 
    }
    

    9.2 指定类型参数

    function combine<T>(arr1: T[], arr2: T[]): T[] {
      return arr1.concat(arr2)
    }
    combine([1, 2, 3], [4, 5, 6])
    
    // 报错了, 因为类型推断为number[]
    // combine([1, 2, 3], ["a", "b", "c"])
    
    // 如果你非得乱搞,那需要这样做, 声明数组的类型
    let arr = combine<number | string> ([1, 2, 3], ["a", "b", "c"])
    console.log(arr)//[LOG]: [1, 2, 3, "a", "b", "c"] 
    

    9.3 泛型约束

    interface haveLength {
        length: number
    }
    // 传入的参数需要有length属性
    function use<T extends haveLength>(args: T) {
        console.log(args.length)
    }
    use("123")//[LOG]: 3
    

    9.4 泛型约束中使用类型参数

    function getProperties<Type, Key extends keyof Type>(t: Type, k: Key) {
        return t[k]
    }
    let obj = {
        a: 1,
        b: 2
    }
    let ret1 = getProperties(obj, "a")
    console.log(ret1)//[LOG]: 1 
    
    //let ret2 = getProperties(obj, "c")//报错, 没有这个key
    

    十. This关键字

    • this的指向问题
      在 TypeScript 中,你可以在函数参数中使用 this 参数,这允许你显式地指定函数的调用方。通常,在函数内部,this 关键字用于引用当前对象,但对于一些情况,尤其是在回调函数或异步代码中,JavaScript 的默认行为可能导致 this 的值不是你期望的对象。

    • this和箭头函数, 注意:this在冒号前面.如果this在冒号后面,this就是指向调用方

    class MyClass {
        name = "MyClass"
        getName() {
            return this.name
        }
        getConstName = () => {
            return this.name
        }
        getThisName(this: MyClass) {
            return this.name
        }
    }
    
    //没问题
    let cls = new MyClass()
    console.log(cls.getName())//[LOG]: "MyClass" 
    
    //换个方式就有问题了
    //getName获取到的是cls1的, 而不是MyClass的
    let cls1 = {
        name: "cls1Name",
        getName: cls.getName//这是一个方法
    }
    console.log(cls1.getName())//[LOG]: "cls1Name" 
    
    
    //怎么强行输出MyClass呢.
    //1.使用=>, 把方法改成函数
    let cls2 = {
        name: "cls2Name",
        getName: cls.getConstName//这是一个方法
    }
    console.log(cls2.getName())//[LOG]: "MyClass" 
    //2.使用this关键字
    let cls3 = {
        name: "cls3Name",
        getName: cls.getThisName
    } 
    console.log(cls3.getName())//报错, 直接不让cls3使用自己的name,只能使用MyClss的name
    

    F

    1. type和interface的区别
      基本相同, 但是interface更容易扩展
    //type后面跟个=
    type Cls0 = {
      a: number
    }
    let a0: Cls0 = {a: 10}
    //使用&符号type增加扩展
    type Cls1 = Cls0 & {
      b: number
    }
    let a1: Cls1 = {a: 10, b: 20}
    console.log(a1)
    
    
    //interface后面没有=
    interface Bill{ 
      a: number
    }
    let b0: Bill = {a: 10}
    // 使用extend增加扩展
    interface Bill1 extends Bill {
      b: number
    }
    let b1: Bill1 = {a: 10, b: 20}
    console.log(b1)
    
    
    //使用extend给type增加扩展  0.0
    interface Cls2 extends Cls0 {
      c: number
    }
    let c: Cls2 = {a: 10, c: 30}
    console.log(c)
    
    
    //interface可以多地方声明. type多地方声明则会报错
    interface Win {
      a: string
    }
    interface Win {
      b: number
    }
    const w: Win = {
      a: "this is a stirng",
      b: 666
    }
    console.log(w)
    

    相关文章

      网友评论

          本文标题:TypeScript基础语法

          本文链接:https://www.haomeiwen.com/subject/lycnidtx.html