TS笔记

127 阅读5分钟

1、类型注解和类型推断

  • 在typescript中,类型注解(type annotation)和类型推断(type inference)是用来确定变量、函数和表达式类型得俩种方法。

2、类型注解

  • 类型注解是明确的给变量、函数参数、函数返回值或表达式指定类型的方式。使用“ : ”后跟类目名称来注解。
    let age: number = 30;
    function greet(name: string): string {
        return 'heelo'+name
    }
    
    // 这个例子中的,age、name、greet()的返回值,都用了类型注解。
    

3、类型推断

  • 类型推断是TypeScript的一种功能,根据变量的赋值表达式自动推断出变量的类型。ts会根据上下文和赋值的类型去推断出变量的类型,而无需再显式注解

4、泛型

  • 当数据类型不是固定的时候,可以使用泛型将数据类型变成动态的。也就是先不定义数据的一个具体类型,当使用的时候再指定。

5、函数里的泛型

  • 在函数名后面跟上<T> ,其中 T 就是动态的类型,形参 value 的类型也就是 T ,返回的也是一个 T 类型的数组。当调用函数的时候,在函数名后面传入需要定义的数据类型<string>,此时函数内部所有 T 都会被替换成 string
    // 泛型可以定义多个。
    function getData<T, K>(value: T, value: K): Array<T | K> {
        return [value1, value2]
    }
    getData(1, 2)
    getData<string, number>("3", 4)
    getData(true, null)
    

6、泛型接口

  • interface或者type中也是可以使用泛型,用法一样。
    interface ResData<T> {
        code: number,
        msg: string,
        data: T
    }
    
    const response: ResData<boolean> = {
        code: 1,
        msg: 'success',
        data: false
    }
    
    type Data<K> = number | string | K
    const data: Data<null> = null
    

7、泛型变量

  • 看别人的ts代码会看到很多泛型 T、E、V... 之类的变量,为什么有的地方是T,有的地方是VTypeScript在这方面没有强制性要求,都是开发者们为了方便阅读理解,默认形成得一套规范。
    • T:表示一般的泛型类型参数。
    • K:表示对象中的键类型。
    • V:表示对象中的值类型。
    • E:表示数组或元组中的元素类型。
    • R:表示函数的返回类型。
    • S,U,V,...:表示额外的泛型类型参数。

8、泛型约束

  • 函数内部使用泛型时,还不知道是什么类型,也就不能使用、操作数据的属性或者方法
    function test<T>(name: T): void {
        console.log('name length', name.length)
        // 类型 T 不存在属性 length
    }
    
  • 此时就可以使用泛型约束,对使用的泛型数据进行约束,约束为具有length属性的类型,如 string、Array
  • 语法:<T extends 类型>
    • 这里定义一个 Len 接口类型里面的属性有个length,而赋值给它的类型,要是没有length属性,就会报错。
      interface Len {
          length: number
      }
      
      function test<T extends Len>(name: T): void {
          console.log('name length', name.length)
      }
      
      test('1')
      test([1,2,3])
      test(2) // 类型 number 的参数不能赋值给类型 Len 的参数
      test(false) // 类型 boolean 的参数不能赋值给类型Len 的参数
      

9、泛型和any的差别

  • any 类型
    • any类型允许你将任何类型分配给它,而TypeScript不会进行任何类型检查。这样的灵活性也带来了潜在的问题,因为你可能会意外的使用错误的类型,而在编译时不会得到任何警告
      let myVar: any = 10;
      myVar = 'Hello'; 
      // any 失去类型检查,不管插入什么值都可以。
      
  • 泛型
    • 泛型是一种用于创建可重用代码的工具,它允许你编写与类型无关的代码。通过使用泛型,你可以编写一些函数或类,它们可以使用于多种类型而不失去类型安全性。
    • 泛型允许你在使用函数或类的时候指定类型,从而在编译时进行类型检查。
      // 使用泛型
      function identity<T>(arg: T): T {
          return arg
      }
      let result: stirng = identity("hello")
      // 此时既有灵活性,又保证了类型的安全。
      
  • 总结
    • any 提供了更大的灵活性,但也失去了类型的安全性。而泛型则是在保持类型安全的同时提供了一定的灵活性
    • 在上面案例中,函数 identity 接收一个泛型参数 arg ,并声明一个局部变量 result ,其类型也是 T 。这确保了 result 的类型与传入的参数类型相同。 泛型 T 在函数内部的使用是一种类型一致性的保证,让函数可以灵活地处理不同类型的输入数据,同时保持类型安全

10、type和interface的区别?

1、共同点:

  • 基本用法相似:

    • 都可以用来定义对象的形状。
    • 都可以用来描述函数、数组等类型。
    type PointType = {
      x: number;
      y: number;
    };
    
    interface PointInterface {
      x: number;
      y: number;
    } 
    
  • 都可以用于描述函数类型:

    type AddType = (a: number, b: number) => number;
    
    interface AddInterface {
      (a: number, b: number): number;
    }
    

2、区别:

  • 扩展(扩展性):

    • interface 可以通过 extends 扩展,可以继承多个接口。
    • type 可以通过交叉类型&)进行组合,但不能继承
    interface Animal {
      name: string;
    }
    
    interface Dog extends Animal {
      breed: string;
    }
    
    type AnimalType = {
      name: string;
    };
    
    type DogType = AnimalType & {
      breed: string;
    }; 
    
  • 声明合并:

    • interface 可以进行声明合并,即多个同名接口自动合并为一个接口。
    • type 不支持声明合并,如果定义多个同名 type 会报错。
    interface Person {
      name: string;
    }
    
    interface Person {
      age: number;
    }
    
    // 合并后
    // interface Person {
    //   name: string;
    //   age: number;
    // }
    
    type PersonType = {
      name: string;
    };
    
    type PersonType = {
      age: number;
    }; // Error: Duplicate identifier 'PersonType'.
    
  • 使用范围:

    • type 可以声明任何类型,包括基本类型联合类型交叉类型元组等。
    • interface 主要用于声明对象类型。
    type Name = string;
    type Union = string | number;
    type Tuple = [number, string]; 
    
  • 可选属性和只读属性:

    • typeinterface 都支持可选属性(?)和只读属性(readonly)。
    type PointType = {
      readonly x: number;
      y?: number;
    };
    
    interface PointInterface {
      readonly x: number;
      y?: number;
    } 
    
  • 类型别名的高级功能:

    • type 可以使用映射类型条件类型模板字面量类型等高级类型功能。
    type Keys = "a" | "b" | "c";
    type Flags = { [K in Keys]: boolean };
    
    type ConditionalType<T> = T extends string ? string : number;
    
    type TemplateLiteralType = `${Keys}_suffix`;
    

3、选择建议

  • 使用 interface

    • 如果需要使用声明合并特性。
    • 如果需要扩展实现一个接口
    • 如果编写框架,建议使用接口,因为它的扩展性更强
  • 使用 type

    • 如果需要使用高级类型(如联合类型交叉类型映射类型条件类型)。
    • 如果需要定义基本类型别名联合类型元组类型等。
    • 如果不需要使用接口的扩展声明合并特性

11、联合类型、交叉类型、映射类型、条件类型、模板字面量类型、元组类型是什么?

1、简述:

  • 联合类型: 定义一个变量可以是多种类型之一
  • 交叉类型: 合并多个类型为一个新类型,包含所有原类型属性
  • 映射类型: 基于已有类型创建一个新类型,常用于添加修饰符
  • 条件类型: 根据条件表达式选择类型,实现类型的动态选择推断
  • 模板字面量类型: 用于生成基于字符串模板的类型。
  • 元组类型: 表示已知元素数量类型的数组,每个元素可以有不同的类型

2、详解:

  • 联合类型

    • 联合类型表示一个变量可以是几种类型之一。使用竖线 (|) 分隔各个类型。
    type StringOrNumber = string | number;
    let value: StringOrNumber;
    
    value = "hello"; // valid
    value = 123; // valid
    value = true; // error 
    
  • 交叉类型

    • 交叉类型将多个类型合并为一个类型。使用与符号 (&) 连接各个类型。结果类型包含所有合并类型的所有属性。
    type Person = {
      name: string;
    };
    type Employee = {
      id: number;
    };
    type PersonEmployee = Person & Employee;
    
    let employee: PersonEmployee = {
      name: "John",
      id: 123
    }; 
    
  • 映射类型

    • 映射类型根据一个已有的类型创建一个的类型。可以使用 in 关键字遍历一个联合类型,并对每个成员应用一个转换
    type Keys = "a" | "b" | "c";
    type Flags = { [K in Keys]: boolean };
    
    // Resulting type:
    // type Flags = {
    //   a: boolean;
    //   b: boolean;
    //   c: boolean;
    // } 
    
    • 映射类型常用于创建带有特定修饰符(如可选、只读)的类型。
    type Readonly<T> = { readonly [P in keyof T]: T[P] };
    type Partial<T> = { [P in keyof T]?: T[P] }; 
    type User = {
      id: number;
      name: string;
    };
    
    type ReadonlyUser = Readonly<User>;
    type PartialUser = Partial<User>;
    
  • 条件类型

    • 条件类型根据一个条件表达式在类型之间进行选择。
    • 语法是 T extends U ? X : Y
    type IsString<T> = T extends string ? "yes" : "no";
    
    type A = IsString<string>; // "yes"
    type B = IsString<number>; // "no"
    
    • 条件类型还可以用于类型推断和复杂类型转换。
    type Exclude<T, U> = T extends U ? never : T;
    type NonNullable<T> = T extends null | undefined ? never : T;
    
    type T0 = Exclude<"a" | "b" | "c", "a">; // "b" | "c"
    type T1 = NonNullable<string | number | undefined>; // string | number 
    
  • 模板字面量类型

    • 模板字面量类型允许在类型中使用字符串模板字面量。它可以用于构建复杂的字符串类型。
    • 模板字面量类型可以用于字符串操作,如拼接、条件匹配等。
    type Color = "red" | "green" | "blue";
    type ColorVariant = `${Color}-light` | `${Color}-dark`;
    
    // Resulting type:
    // type ColorVariant = "red-light" | "green-light" | "blue-light" | "red-dark" | "green-dark" | "blue-dark"
    
  • 元组类型

    • 元组类型表示一个已知元素数量和类型的数组,每个元素可以有不同的类型。
    let tuple: [number, string, boolean];
    
    tuple = [42, "hello", true]; // valid
    tuple = ["hello", 42, true]; // error 
    
    • 元组类型可以通过扩展来支持可选元素和剩余元素。
    // [42] or [42, "hello"]
    type TupleWithOptional = [number, string?];
    
    // [42] or [42, "a", "b", "c"]
    type TupleWithRest = [number, ...string[]];