Skip to main content

泛型

说泛型之前,先了解几个 Typescript 中的操作符:keyoftypeofin

  • keyof,键值获取

    获取一个类型的所有键值,返回一个联合类型:

    type Person = {
      name: string
      age: number
    }
    type PersonKey = keyof Person   // PersonKey得到的类型为 'name' | 'age'
    

    keyof 的一个典型用途是限制访问对象的 key 合法化,any 做索引是不被接受的:

    function getValue(obj: Person, k: any) {
      // return obj[k] // 通不过ts的检查
      return obj[k as keyof Person]
    }
    
  • typeof 实例类型获取

    获取一个对象/实例的类型

    const boy: Person = { name: "jack", age: 12 };
    type P = typeof boy; // P得到的类型是 {name: string, age: number}
    

    typeof 和 keyof 可以一起使用(typeof 返回的是一个类型):

    type PersonKey = keyof typeof boy   // 'name' | 'age'
    
  • in 遍历属性

    in 只能用在类型的定义中,可以对枚举类型进行遍历:

    // 这个类型将任何类型的键值转换为number类型
    type TypeToNumber<T> = {
      [key in keyof T]: number
    }
    

我对于泛型的理解是从官网上读到的一句话:a type variable, a special kind of variable that works on types rather than values.

  • 泛型基本使用

    泛型可用在函数定义,类定义,普通类型定义和接口定义上,枚举和命名空间不能使用泛型。

  • 泛型推导

    TS有时会自动根据变量定义时的类型推导出变量类型,此时就可以省略泛型的显式定义。这一般发生在函数调用的场合。

    function iden<T>(arg: T): T {
      return arg
    }
    
    // 显式指定泛型类型
    iden<string>('name')
    
    // 也可以省略,TS会自动推到泛型类型为number
    iden(23)
    
  • 泛型约束

    function logLen<T>(arg: T): T {
      console.log(arg.length) // 这里会报错
      return arg
    }
    

    上述例子报错是因为不是所有类型都有length属性,因此这里要进行类型约束。

    interface ILen {
      length: number
    }
    function logLen<T extends ILen>(arg: T): T {
      console.log(arg.length)
      return arg
    }
    

    泛型约束中可以使用泛型参数

    function getPro<T, K extends keyof T>(obj: T, key: K) {
      return obj[key]
    }
    

    这里的泛型约束可以确保我们不会获取obj中不存在的属性。

泛型工具

  • Partial<Type>

    Type中的所有属性变为可选的。

    type Partial<T> = {
      [K in keyof T]?: T[k]
    }
    
  • Required<Type>

    Partial作用相反,将Type中的可选属性变为必选

  • Record<Keys, Type>

    创建一个对象类型,其属性key是Keys,属性值是Type。作用:map the properties of a type to another type

    type Record<K extends string | number | symbol, T> = {[P in K]: T}
    
  • Pick<Type, Keys>

    Type中选出Keys键列表,生成新的类型

    type Pick<T, K extends keyof T> = {
      [P in K]: T[P]
    }
    
  • Exclude<T, U>

    在T类型中,去除T类型和U类型的交集,返回剩余的部分

    type Exclude<T, U> = T extends U ? never : T
    

    注意后面的T指的是T中和U无交集的部分。

  • Omit<Type, Keys>

Type中移除Keys键,返回剩余的键

type Omit<T, K extends string | number | symbol> = {
  [P in Exclude<keyof T, K>]: T[P]
}
  • ReturnType<Type>

获取函数类型Type的返回类型,举个例子:

function foo(x: string | number): string | number {}

type FooType = ReturnType<foo>   // string | number

参考:

官方文档--泛型

TypeScript 高级用法