• Ts是什么?


    Ts是什么?

    Ts:是TypeScript的简称,是一种由微软开发的自由和开源的编程语言。

    ts和js之间有什么关系

    • ts是js的超集,简单来说就是在js的基础上加入了类型系统,让每个参数变的有明确的意义,且带来了更加智能的提示。
    • 相对于js来说,ts属于强类型语言,所以对于项目而言,会使代码规范起来,从而解决了大型项目代码的复杂性,但是浏览器是不识别ts的,所以编译的时候需要编译成js文件

    ts的安装

    npm install -g typescript 
    //或
    yarn global add typescript
    
    tsc -v //查看版本
    
    • 1
    • 2
    • 3
    • 4
    • 5

    在线编译:https://www.typescriptlang.org/play

    基本数据类型

    • 基本类型:string、number、boolean、symbol、bigint、null、undefined
    • 引用类型:array、 Tuple(元组)、 object(包含Object和{})、function
    • 特殊类型:any、unknow、void、nerver、Enum(枚举)
    • 其他类型:类型推理、字面量类型、交叉类型

    基本类型

    //字符串
    let str: string = "Domesy"
    
    // 数字
    let num: number = 7
    
    //布尔
    let bool: boolean = true
    
    //symbol
    let sym: symbol = Symbol();
    
    //bigint 用来表示那些已经超出了 number 类型最大值的整数值,对于总是被诟病的整数溢出问题,使用了 bigint 后将完美解决
    let big: bigint = 10n
        
    //null
    let nu: null = null
    
    //undefined
    let un: undefined = undefined
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 注意:
    • null 和 undefined 两个类型一旦赋值上,就不能在赋值给任何其他类型
    • symbol是独一无二的,假设再定义一个 sym1,那么sym === sym1 为 false

    引用类型

    Array 两种方式

    • 类型名称+[]
    • Array<数据类型>
    let arr1:number[] = [1,2,3]
    let arr2:Array = [1,2,3]
    let arr3:Array = [1,2,'3'] // 报错
    
    let arr4:Array = [1,2,'3']
    
    • 1
    • 2
    • 3
    • 4
    • 5

    Tuple(元组)

    Tuple可以说是Array的一种特殊情况,针对上面的arr3,类型是string或者number,但对每个元素没有做出具体的限制。

    Tuple 的作用就是限制元素的类型并且限制个数的数组,同时 Tuple这个概念值存在于TS,在JS上是不存在的

    注意:在ts中,是允许对Tuple扩增(数组的push),但在访问上不允许。

    let t: [number, string] = [1, '2'] // ok
    let t1: [number, string] = [1, 3] // error
    let t2: [number, string] = [1] // error
    let t3: [number, string] = [1, '1', true] // error
    
    
    let t5: [number, string] = [1, '2'] // ok
    t.push(2)
    console.log(t) // [1, '2', 2]
    
    let a =  t[0] // ok
    let b = t[1] // ok
    let c = t[2] // error
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    object

    • object非原始类型,在定义上直接使用是可以的,但是要修改对象的属性会报错,是因为对对象的内部具体的属性做了限制,所以需要使用{}来定义内部类型
    let obj1:object={
        a: 1,
        b: 2
    }
    obj1.a = 3 // error
    
    let obj2: { a: number, b: number } = {
        a: 1, 
        b: 2
    }
    obj2.a = 3 // ok
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • Object(大写的O),代表所有的原始类型或非原始类型都可以进行赋值,除了null和undefined
    let obj: Object;
    obj = 1; // ok
    obj = "a"; // ok
    obj = true; // ok
    obj = {}; // ok
    obj = Symbol() //ok
    obj = 10n //ok
    obj = null; // error
    obj = undefined; // error
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    function

    定义函数

    • 两种方式,一种是function,一种是箭头函数
    • 在书写的时候,可以写入返回值的类型,如果写入,必须要有对应类型的返回值.通常情况下是省略,因为TS的类型推断功能够正确推断出返回值类型
    function setName1(name: string) { //ok
        console.log("hello", name);
    }
    setName1("Domesy"); // "hello",  "Domesy"
    
    function setName2(name: string):string { //error 函数没有返回值
        console.log("hello", name);
    }
    setName2("Domesy");
    
    function setName3(name: string):string { //error 函数的返回值是 number
        console.log("hello", name);
        return 1
    }
    setName3("Domesy");
    
    function setName4(name: string): string { //ok 函数的返回值是string
        console.log("hello", name);
        return name
    }
    setName4("Domesy"); // "hello",  "Domesy"
    
    //箭头函数与上述同理
    const setName5 = (name:string) => console.log("hello", name);
    setName5("Domesy") // "hello",  "Domesy"
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25

    参数类型

    • 可选参数:通过?实现
    • 默认参数:函数内可以自己设定其默认参数,用 = 实现
    • 剩余参数:仍可以使用扩展运算符 …
    // 可选参数
    const setInfo1 = (name: string, age?: number) => console.log(name, age)
    setInfo1('Domesy') //"Domesy",  undefined
    setInfo1('Domesy', 7) //"Domesy",  7
    
    // 默认参数
    const setInfo2 = (name: string, age: number = 11) => console.log(name, age)
    setInfo2('Domesy') //"Domesy",  11
    setInfo2('Domesy', 7) //"Domesy",  7
    
    // 剩余参数
    const allCount = (...numbers: number[]) => console.log(`数字总和为:${numbers.reduce((val, item) => (val += item), 0)}`)
    allCount(1, 2, 3) //"数字总和为:6"
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    特殊类型

    any

    在ts中,任何类型都归于any类型,所以any类型就成了顶级类型,如果不指定变量的类型,默认是any类型,不推荐使用该类型,因为这样丧失了ts的作用

    let d:any; //等价于 let d 
    d = '1';
    d = 2;
    d = true;
    d = [1, 2, 3];
    d = {}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    unknow

    与any一样,都可以作为顶级类型,但是它更加严格,主要严格在于

    • unknow会对值进行检测,而类型any不会做检测操作,说白了,any类型可以赋值给任何类型,但unknow只能赋值给unknow类型和any类型
    • unknow不允许定义的值有任何操作(如 方法,new等),但any可以
    let u:unknown;
    let a: any;
    
    u = '1'; //ok
    u = 2; //ok
    u = true; //ok
    u = [1, 2, 3]; //ok
    u = {}; //ok
    
    let value:any = u //ok
    let value1:any = a //ok
    let value2:unknown = u //ok
    let value3:unknown = a //ok
    let value4:string = u //error 只能赋值给unknown或者any类型
    let value5:string = a //ok
    let value6:number = u //error 只能赋值给unknown或者any类型
    let value7:number = a //ok
    let value8:boolean = u //error 只能赋值给unknown或者any类型
    let value9:boolean = a //ok
    
    u.set() // error unknow不允许定义的值有任何操作
    a.set() //ok
    u() // error unknow不允许定义的值有任何操作
    a() //ok
    new u() // error unknow不允许定义的值有任何操作
    new a() //ok
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26

    void

    当一个函数,没有返回值时,TS会默认他的返回值为 void 类型

    const setInfo = ():void => {} // 等价于 const setInfo = () => {}
    
    const setInfo1 = ():void => { return '1' }  // error
    const setInfo2 = ():void => { return 2 } // error
    const setInfo3 = ():void => { return true } // error
    const setInfo4 = ():void => { return  } // ok
    const setInfo5 = ():void => { return undefined } //ok
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    never

    表示一个函数永远不存在返回值,TS会认为类型为 never,那么与 void 相比, never应该是 void子集, 因为 void实际上的返回值为 undefined,而 never 连 undefined也不行

    符合never的情况有:当抛出异常的情况和无限死循环

    let error = ():never => { 
        // 等价约 let error = () => {}
        throw new Error("error");
    };
    
    let error1 = ():never => {
        while(true){}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    枚举

    字符串枚举

    注意:字符串枚举要注意的是必须要有默认值,不支持反向映射

    enum sex {
       male = "男",
       female = "女",
       unknown = "未知",
      // name, //这么写报错,无默认值
    }
    // 这么写 就不报错
    enum sex {
       name, //这么写不报错,有默认值 0
       male = "男",
       female = "女",
       unknown = "未知",
    }
    console.log(sex)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    打印结果:

    {
        female: "女"
        male: "男"
        unknown: "未知"
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    数字枚举

    • 枚组的类型默认为数字类型,默认从0开始以此累加,如果有设置默认值,则只会对下面的值产生影响
    • 同时支持反向映射(及从成员值到成员名的映射),但智能映射无默认值的情况,并且只能是默认值的前面
    enum color {
        black, // 默认是0
        red = 10, //默认不是0 而是 10 只会对下面的值产生影响
        green,
        yellow, 
     }
    console.log(color)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    打印结果:

    {
        0: 'black'
        10: 'red', 
        11: 'green', 
        12: 'yellow', 
        balck: 0,
        red: 10, 
        green: 11, 
        yellow: 12
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    常量枚举

    • 除了数字类型和字符串类型之外,还有一种特殊的类型,那就是常量枚组,也就是通过const去定义enum,但这种类型不会编译成任何 JS,只会编译对应的值
    const enum sta {
      A,
      B,
      C=7,
      D
    }
    console.log(sta);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    打印结果

    0: "A"
    1: "B"
    7: "C"
    8: "D"
    A: 0
    B: 1
    C: 7
    D: 8
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    常量枚举

    • 包含了 数字类型 和 字符串类型 的混合,反向映射一样的道理
    enum sex {
        a,
        b = "ba",
        c = 7,
        d
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    打印结果

    0: "a"
    7: "c"
    8: "d"
    a: 0
    b: "ba"
    c: 7
    d: 8
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    枚举的合并,不会覆盖 会直接合并

    enum sex{
        ci = "雌",
        xiong = "雄",
    }
    enum sex {
      male = "男",
      female = "女",
      unknown = "未知",
    }
    console.log(sex)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    类型推论

    在TS中如果不设置类型,并且不进行赋值时,将会推论为any类型,如果进行赋值就会默认为类型

    let a; // 推断为any
    let str = '小杜杜'; // 推断为string
    let num = 13; // 推断为number
    let flag = false; // 推断为boolean
    
    str = true // error Type 'boolean' is not assignable to type 'string'.(2322)
    num = 'Domesy' // error
    flag = 7 // error
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    字面量类型

    字面量类型:在TS中,我们可以指定参数的类型是什么,目前支持字符串、数字、布尔三种类型。比如说我定义了 str 的类型是 ‘小杜杜’ 那么str的值只能是小杜杜

    let str:'小杜杜' 
    let num: 1 | 2 | 3 = 1
    let flag:true
    
    str = '小杜杜' //ok
    str = 'Donmesy' // error
    
    num = 2 //ok
    num = 7 // error
    
    flag = true // ok
    flag = false // error
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    交叉类型

    将多个类型合并为一个类型,使用&符号连接,如:

    type AProps = { a: string }
    type BProps = { b: number }
    
    type allProps = AProps & BProps
    
    const Info: allProps = {
        a: '小杜杜',
        b: 7
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    TS断言和类型守卫

    • 分为三种:类型断言、非空断言、确定赋值断言

    类型断言

    类型断言会告诉编译器,你不用给我进行检查,相信我,他就是这个类型

    • 尖括号
    • as:推荐
    //尖括号
    let num:any = '小杜杜'
    let res1: number = (num).length; // React中会 error
    
    // as 语法
    let str: any = 'Domesy';
    let res: number = (str as string).length;
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    注意:尖括号语法在react中会报错,原因是与jsx语法会产生冲突,所以只能使用as语法

    非空断言

    • 在上下文中当类型检查器无法断定类型时,一个新的后缀表达式操作符 ! 可以用于断言操作对象是非 null 和非 undefined 类型。
    let name:string = 'huxngxiaoguo'
    
    let nus:string;
    
    console.log(name.trim())
    
    //非空断言操作符 !  可以消除编辑器 当nus为undefined时候报错
    //使用时注意 保证nus不为undefined,否则运行时会报错
    console.log(nus!.trim())
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    function myFunc(maybeString: string | undefined | null) {
      const onlyString: string = maybeString; // Error
      const ignoreUndefinedAndNull: string = maybeString!; // Ok
    }
    
    • 1
    • 2
    • 3
    • 4

    确定赋值断言

    允许在实例属性和变量声明后面放置一个 ! 号,以告诉TS该属性会被明确赋值。

    let num: number;
    let num1!: number;
    
    const setNumber = () => num = 7
    const setNumber1 = () => num1 = 7
    
    setNumber()
    setNumber1()
    
    console.log(num) // error 
    console.log(num1) // ok
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    类型守卫

    • 是可执行运行时检查的一种表达式,用于确保该类型在一定的范围内
    • 常有的类型守卫共有4种:in关键字、typeof关键字、interfaceof关键字和类型谓词(is)

    in关键字

    • 用于判断这个属性是那个里面的
    interface Info {
        name: string
        age: number
    }
    
    interface Info1{
        name: string
        flage: true
    }
    
    const setInfo = (data: Info | Info1) => {
        if("age" in data){
        console.log(`我的名字是:${data.name},年龄是:${data.age}`)
        }
    
        if("flage" in data){
        console.log(`我的名字是:${data.name},性别是:${data.flage}`)
        }
    }
    
    setInfo({name: '小杜杜', age: 7}) // "我的名字是:小杜杜,年龄是:7" 
    setInfo({name: '小杜杜', flage: true}) // "我的名字是:小杜杜,性别是:true"
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    typeof关键字
    用于判断基本类型,如string | number等

    const setInfo = (data: number | string | undefined) => {
        if(typeof data === "string"){
            console.log(`我的名字是:${data}`)
        }
    
        if(typeof data === "number"){
            console.log(`我的年龄是:${data}`)
        }
    
        if(typeof data === "undefined"){
            console.log(data)
        }
    }
    
    setInfo('小杜杜') // "我的名字是:小杜杜"  
    setInfo(7) // "我的年龄是:7" 
    setInfo(undefined) // undefined" 
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    interfaceof关键字
    用于判断一个实例是不是构造函数,或使用类的时候

    class Name {
        name: string = '小杜杜'
    }
    
    class Age extends Name{
        age: number = 7
    }
    
    const setInfo = (data: Name) => {
        if (data instanceof Age) {
            console.log(`我的年龄是${data.age}`);
        } else {
            console.log(`我的名字是${data.name}`);
        }
    } 
    
    setInfo(new Name()) // "我的名字是小杜杜"
    setInfo(new Age()) // "我的年龄是7" 
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    类型谓词(is)

    function isNumber(x: any): x is number { //默认传入的是number类型
      return typeof x === "number"; 
    }
    
    console.log(isNumber(7)) // true
    console.log(isNumber('7')) //false
    console.log(isNumber(true)) //false
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    断言与类型守卫的区别

    • 断言与类型守卫的概念非常相似,都是确定参数的类型,但断言更加霸道,它是直接告诉编辑器,这个参数就是这个类型,而类型守卫更像确定这个参数具体是什么类型

    接口interface

    接口可以用来描述对象,主要可以包括以下数据:可读属性、只读属性、任意属性

    • 可读属性:当我们定义一个接口时,我们的属性可能不需要全都要,这是就需要 ? 来解决
    • 只读属性:用 readonly修饰的属性为只读属性,意思是指允许定义,不允许之后进行更改
    • 任意属性:这个属性极为重要,它是可以用作就算没有定义,也可以使用,比如 [data: string]: any。比如说我们对组件进行封装,而封装的那个组件并没有导出对应的类型,然而又想让他不报错,这时就可以使用任意属性
    interface Props {
        a: string;
        b: number;
        c: boolean;
        d?: number; // 可选属性
        readonly e: string; //只读属性
        [f: string]: any //任意属性
    }
    let res: Props = {
        a: '小杜杜',
        b: 7,
        c: true,
        e: 'Domesy',
        d: 1, // 有没有d都可以
        h: 2 // 任意属性,之前为定义过h
    }
    
    let res.e = 'hi' // error, 原因是可读属性不允许更改
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    继承

    继承:与类一样,接口也存在继承属性,也是使用extends字段

    interface nameProps {
        name: string
    }
    
    interface Props extends nameProps{
        age: number
    }
    
    const res: Props = {
        name: '小杜杜',
        age: 7
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    泛型

    泛型是允许同一个函数接受不同类型参数的一种模版,与any相比,使用泛型来创建可服用的组件要更好,因为泛型会保留参数类型(PS:泛型是整个TS的重点,也是难点,请多多注意~)

    为什么需要泛型
    我们先看看一个例子:

    const calcArray = (data:any):any[] => {
        let list = []
        for(let i = 0; i < 3; i++){
            list.push(data)
        }
        return list
    }
    
    console.log(calcArray('d')) // ["d", "d", "d"]
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 上述的例子我们发现,在calcArray中传任何类型的参数,返回的数组都是any类型
    • 由于我们不知道传入的数据是什么,所以返回的数据也为any的数组
    • 但我们现在想要的效果是:无论我们传什么类型,都能返回对应的类型,针对这种情况怎么办?所以此时泛型就登场了

    泛型语法

    const calcArray = (data:T):T[] => {
        let list:T[] = []
        for(let i = 0; i < 3; i++){
            list.push(data)
        }
        return list
    }
    
    const res:string[] = calcArray('d') // ok
    const res1:number[] = calcArray(7) // ok
    
    type Props = {
        name: string,
        age: number
    }
    const res3: Props[] = calcArray({name: '小杜杜', age: 7}) //ok
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    经过上面的案例,我们发现传入的字符串、数字、对象,都能返回对应的类型,从而达到我们的目的,接下来我们再看看泛型语法:

    function identity (value:T) : T {
        return value
    }
    
    • 1
    • 2
    • 3

    第一次看到这个我们是不是很懵,实际上这个T就是传递的类型,从上述的例子来看,这个就是,要注意一点,这个实际上是可以省略的,因为 TS 具有类型推论,可以自己推断类型

    多类型传参

    const calcArray = (name:T, age:U): {name:T, age:U} => {
        const res: {name:T, age:U} = {name, age}
        return res
    }
    
    const res = calcArray('小杜杜', 7)
    console.log(res) // {"name": "小杜杜", "age": 7}
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    泛型接口

    定义接口的时候,我们也可以使用泛型

    interface A {
        data: T
    }
    
    const Info: A = {data: '1'}
    console.log(Info.data) // "1"
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
  • 相关阅读:
    一文带你深入浅出C语言文件操作
    Unity接入日志插件Log4Net
    玩转Python:数据可视化,一个很高级的交互式Python库,附代码
    鲁棒局部均值分解 (RLMD)附Matlab代码
    据说是中国电信的java编程面试题
    函数指针
    微信小程序WXS
    全志R128适配 ST7789v LCD
    用java刷点题-lc101. 对称二叉树
    BA-NeRF ICCV 2021
  • 原文地址:https://blog.csdn.net/lbPro0412/article/details/126035641