infer
言简意赅,infer就是推导泛型参数
infer声明只能出现在extends子语句中
infer后面跟一个变量名
简单的例子:获取Promise的返回值
interface User {
name: 'zl',
age: 18
}
type Res = Promise<User>;
type PromiseUser<T> = T extends Promise<infer U> ? U : T;
type r = PromiseUser<Res>;
如果遇到了多层的情况可以使用递归
interface User {
name: 'zl',
age: 18
}
type Res = Promise<User>;
type PromiseUser<T> = T extends Promise<infer U> ? PromiseUser<U> : T;
type r= PromiseUser<Res>;
infer的协变
举例:取对象属性的类型并且返回元组类型
let obj = {
name: 'zl',
age: 18
}
type InferUser<T> = T extends { name: infer N, age: infer A } ? [N, A] : T
type r = InferUser<typeof obj>;
如果同一个对象使用一个变量就会产生协变,返回值就是联合类型
let obj = {
name: 'zl',
age: 18
}
type InferUser<T> = T extends { name: infer N, age: infer N } ? N : T
type r = InferUser<typeof obj>;
infer的逆变
出现在函数的参数上面,逆变返回的是交叉类型
举例
type Bar<T> = T extends {
a: (x: infer U) => void,
b: (x: infer U) => void
} ? U : never
type b = Bar<{ a: (x: string) => void, b: (x: number) => void }>
函数会产生逆变,此时返回的值是一个交叉类型 string & number,怎么可能一个类型同时是string又是number,这种情况不可能,b类型所以是never
总结
在协变位置上同一个类型变量的多个候选类型会被推断为联合类型;在逆变位置上,同一个类型变量的多个候选类型则会被推断为交叉类型