Distributive Conditional Types
重点阅读:www.typescriptlang.org/docs/handbo…
关于extends的一些行为:juejin.cn/post/684490…
T extends U 的情况下,两个类型都是联合类型,行为比较诡异
【个人理解】本质上下述 extends 行为分解为: ‘a’(T) extends 'a'(U),‘a’(T) extends 'c'(U),‘b’(T) extends 'a'(U),‘b’(T) extends 'c'(U),当全部满足 extends 的时候所以 C 才为 ‘true‘。
貌似这种理解方法,在下方的高级类型中都可以行得通。
type T = 'a' | 'b'
type U = 'a' | 'c'
type C = T extends U ? 'true' : 'false'
Partical
type Partical<T> = {
[K in keyof T]?: T[k]
}
Required
- 符号:
1. -? 抹除 optional
2. -readonly 移除 readonly
type Required<T>{
[K in keyof T]-?: T[K]
}
Readonly
type Readonly<T>{
readonly [K in keyof T]: T[K]
}
Record
// key 的类型为 string | number | symbol
// keyof 返回一个对象的key, JS 中 key 只能是 string/numher/symbol 之一
type key = keyof any
type Record <K extends keyof any, T> = {
[P in K]: T
}
Pick
Pick是从给定的 T 中选中其中的 key。
属性不能被省略
type Pick<T, K extends keyof T> = {
[P in K]: T[P]
}
Exclude
适用于联合类型,从 Type 中剔除 Union
type Exclued<T, U> = T extends U ? never : T
Omit
从 Type 中获取所有的 key,然后从中剔除 Keys 中的 key
type Omit<T, K extends keyof any> = Pick<T, Exclude<keyof T, K>>
Extract
从 Type 中提取所有可以赋值给 Union 的联合类型
type Extract<T, U> = T extends U ? T : never
NonNullable
type NonNullable<T> = T extends null | undefined ? never : T
Parameters
获取函数参数的类型( 元组的方式表达 )
这里的extends 确保 T 是一个函数
type Parameters<T extends (...args: any) => any> = T extends (...arg: infer P) => any : P : never
ConstructorParameters
获取构造函数的参数类型,那么类型收窄到 构造函数就行了。
这里为什么要加 abstract ?
type Parameters<T extends abstract new (...args: any) => any> = T extends abstract new (...arg: infer P) => any : P : never
ReturnType
type ReturnType<T extends (...args: any) => any> = T extends (...args: any) => infer R ? R : any
InstanceType
获取构造函数返回的类型,即ReturnType的构造函数版
type InstanceType<T extends abstract new (...args: any) => any> = T extends abstract new (...arg: any) => infer R : R ? any
ThisParameterType
获取函数的 this 的类型,如果不存在就返回 unknown (如,箭头函数)
type ThisParameterType<T> = T extends (this: infer U, ...args: any[]) => any ? U : unknown
function toHex(this: Number){
return this.toString(16)
}
function numberToString(n: ThisParameterType<typeof toHex>){
return toHex.apply(n)
}
OmitThisParameter
1. 判断 function 是否 this 类型,不存在就直接返回 T
2. 如果存在 this 类型,此时已经被 ThisParameterType 处理,去掉了this。继续验证是否取出了 this,如果是 返回带推导类型的 function type;否则返回 T。
type OmitThisParameter<T> = unknown extends ThisParameterType<T> ? T : T extends (...args: infer A) => infer R ? (...args: A) => R : T
function toHex(this: Number){
return this.toString(16)
}
// 这里去掉了this 参数,然后由设置了新的上下文
const fiveToHex:OmitThisParameter<typeof toHex> = toHex.bind(5)
fiveToHex()
验证 ThisParameterType更改了 function 的类型
function toHex(this: Number){
return this.toString(16)
}
type test = ThisParameterType<typeof toHex>
// crash 报错, expect 0 parameters, get 1
toHex(6)
// carsh 报错, void 的 this 不能赋给 Number 类型的 this
toHex()
注意
1. TS 中只能存在一个名为 this 的参数
2. this 参数的位置必须在第一位
ThisType
Marker for contextual 'this' type:保存函数的 this 类型,并不对类型做任何处理。
--noImplicitThis 选项必须开启
inerface ThisType<T>{}
尝试理解一下,这里 This Type 将 methods 的上下文 this 设置为 D & M,即类型为 ObjectDescriptor<D, M> 的对象。
type ObjectDescriptor<D, M> = {
data?: D;
// methods 中 this 的类型是 D & M
methods: M & ThisType<D & M>
}
function makeObject<D, M>(desc: ObjectDescriptor<D, M>): D & M {
let data: object = desc.data || {}
let methods: object = desc.methods || {}
return {...data, ...methods} as D & M
}
let obj = makeObject({
data : {x: 0, y: 0},
methods: {
moveBy(dx: number, dy: number){
// 加了 ThisType 之后, moveBy方法的 this 类型被将强了
// 在被 makeObject 函数处理签,moveBy中的 this.x 不能存在
// 由于 ThisType 存在,this被加强了,成了 D & M
this.x += dx;
this.y += dy;
}
}
})
// 结构后直接拍平了
obj.x = 10;
obj.y = 20;
obj.moveBy(5, 5);
以下四个方法略,详见:www.typescriptlang.org/docs/handbo…