跳到主要内容

TypeScript类型实现

参考:https://wangtunan.github.io/blog/typescript/challenge.html#%E4%BB%8B%E7%BB%8D

初级​

内置Pick(选取)​

  • Pick表示从一个类型中选取指定的几个字段组合成一个新的类型
tsx
type Person = {
name: string;
age: number;
address: string;
sex: number;
}

type MyPick<T,K extends keyof T> = {
[P in K]:T[P]
}
type PickResult = MyPickPerson, 'name' | 'address'>

代码详解:

  • keyof:操作符提取其属性的名称, K extends keyof T:表示K只能是keyof T的子类型,如果我们在使用Pick的时候传递了不存在于T的字段,会报错:

内置Readonly(只读)​

  • Readonly是用来让所有属性变为只读,其用法为:
ts
type MyReadonly<T> = {
readonly [P in keyof T]:T[P]
}
// 结果:{ readonly name: string; readonly age: number; readonly address:string;readonly sex:number;}
type ReadonlyResult = MyReadonly<Person>

内置Exclude(排除)​

Exclude是排除的意思,它从T类型中排除属于U类型的子集,可以理解成取T对于U的差集,用法如下:

ts
// 结果:'name'|'age'
type ExcludeResult = Exclude<'name'|'age'|'sex', 'sex'|'address'>
// 实现
type MyExclude<T, U> = T extends U ? never : T
  • T extends U:这段代码会从T的子类型开始分发,例如:
ts
T extends U
=> 'name'|'age'|'sex' extends 'sex'|'address'
=> (
'name' extends 'sex'|'address' ? never : 'name' |
'age' extends 'sex'|'address' ? never : 'age' |
'sex' extends 'sex'|'address' ? never : 'sex'
)
=> 'name'|'age'

在类型系统中,属性更多的类型是子类型

  • 子类型是可以赋值给父类型的,也就是 父类型变量 = 子类型变量 是安全的,因为子类型上涵盖了父类型所拥有的的一切属性
  • 如果父类型赋值给子类型就会有问题,因为父类型的属性较少,父类型可能会缺少子类型的属性,因此会发生类型错误

内置Extract(交集)​

Extract<T, U>用来取联合类型T和U的交集,用法如下:

Length(元组的长度)​

ts
type Lenth<T extends any> = T extends {length:number}?T['length']:never

type result = Lenth<[1,2,3]>

代码详解:

  • T extends { length: number; }:判断T是否是{ length: number; }的子类型,如果是则代表T为数组或者类数组。
  • T['length']:取T对象的length属性的值(注意,在TypeScript中不能使用T.length来取值,而应该使用T['length'])

注意,在ts中,取类型的属性,不能使用Type.Prop来获取,应通过Type[prop]中括号来读取属性值 比如:T.length【X】 T['length']) 【√】

中级​

高级​