TypeScript 泛型中的索引、映射对象和条件类型

693 阅读3分钟

一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第12天,点击查看活动详情

索引类型

索引类型顾名思义就是对类型中的索引操作的相关语法,和对象差不多,比如如何获取对象中的所有属性名或者根据属性名获取对象中对应属性名的值,Ts中对类型的操作中,也有这样的特性:

  1. 索引类型查询: 获取类型下的所有属性名。
  2. 索引访问类型: 根据索引访问类型下某个属性的类型值。

索引类型查询

语法使用如下所示, keyof 关键词后面跟一个类型,返回该类型下所有属性名的联合类型。

interface Person {
  name: 'string';
  age: 'number';
}
type T = keyof Person; // 'name' | 'age'

索引访问类型

语法使用如下所示, T[K]类型后面中括号加另一个类型,这另一个类型并不是随便乱填,它这个类型必须能赋值给keyof T返回的类型。

interface Person {
  name: 'string';
  age: 'number';
}
type name = 'name';
type NameType = Person[name]; // 'string'

映射对象类型

可以遍历联合类型并以遍历的所有成员作为属性名类型来形成一个对象类型,它用的关键字是in和js中的遍历for in相似,in的前面是变量的一个一个属性名类型,后面是需要变量的联合类型, 它只能在对象类型中使用,语法如下:

{ [K in T]: U }

使用如下

interface Person {
  name: 'string';
  age: 'number';
}
type PersonKeys = keyof Person; // 'name' | 'age'
type ObjIn = {
  readonly [Key in PersonKeys]?: string
}

如上将PersonKeys遍历一遍生成一个新的对象类型它的属性名和Person一样是不过值类型都是string | undeinfed,并且是只读的。 语法中的±、readonly和?是对属性名的设置也可以可以不设置,根据具体的需求而定。

同态映射类型对象

我们在使用映射对象类型in时也使用了索引类型查询keyof的情况下,就叫做同态映射类型对象。语法如下:

{ [K in keyof T]: X }

同态和非同态有什么区别呢,它会将T类型下属性类型的readonly?一同带来。所以就有了在readonly和?前面添加加减运算符,因为同态会把修饰符一同带来,可以设置不要修饰符。

interface Person {
  name?: 'string';
  readonly age: 'number';
}
type ObjIn = {
  -readonly [Key in keyof Person]-?: string
}

条件类型

就是if语句,条件满足用这个,条件不满足用那个,语法其实三目运算符差不多,只不过功能有限,语法如下:

T extends U ? X : Y

只能用extends做条件运算符,T类型的值能否赋值给U类型的值,满足了返回X类型否则返回Y类型, 结果语句中可以使用T类型和U类型。

type Person = { name: 'string' };
type StudentPerson = { name: 'string', age: number };
type Data = StudentPerson extends Person ? string : number; // string

infer关键字

在extends中的U类型前面添加一个infer, 这样U就可以不是一个固定的类型,你可以不用定义这个U具体是那个类型,TS根据T类型进行推导出U的类型, 这个U类型只能在条件为true的结果语句中使用。

type F = () => number;
// TS会推导出infer后面U的类型时number类型.
type ReturnType<T> = T extends () => infer U ? U : any;
type RType = ReturnType<F>; // number