类型推断 infer
是做为 extends
条件类型的子语句使用,同时在 TS2.8 推出。(若是你不熟悉 extends 条件类型能够查看以前分享的 TypeScript 的 extends 条件类型)html
使用 infer
声明一个类型变量,在 条件类型断定为 true 时生效,例如:typescript
type ExtractSelf<T> = T extends (infer U) ? U : T;
type T1 = ExtractSelf<string>; // string
type T2 = ExtractSelf<() => void>; // () => void
type T3 = ExtractSelf<Date[]>; // Date[]
type T4 = ExtractSelf<{ a: string }>; // { a: string }
复制代码
上面的 infer U
语句就是声明一个类型变量 U(它能够是任意字母或单词),变量 U 会解析 T 类型。数组
这里的解析规则很简单: U 等于 T,而后返回 U。(根据执行优先级,这里能够去掉 infer 语法两边的括号 ()
,而有时必须加上,例如:(infer U)[]
)函数
上面的例子只是方便咱们认识它,实际场景不会这么用,由于没有意义。咱们升级上面的写法,用于取出数组中的类型:post
type ExtractArrayItemType<T> = T extends (infer U)[] ? U : T;
// 条件判断都为 false,返回 T
type T1 = ExtractArrayItemType<string>; // string
type T2 = ExtractArrayItemType<() => number>; // () => number
type T4 = ExtractArrayItemType<{ a: string }>; // { a: string }
// 条件判断为 true,返回 U
type T3 = ExtractArrayItemType<Date[]>; // Date
复制代码
经过解析 T 的格式,判断 (infer U)[]
可被分配值 Date[]
,所以条件类型为 true 。而后根据变量 U 所在的位置,推断 U 等于 Date。优化
让咱们再修改一下,实现获取函数返回值类型的功能(相似于官方预置的 ReturnType 高级类型):ui
type ExtractReturnType<T> = T extends () => (infer U) ? U : T;
// 条件判断为 true,返回 U
type T1 = ExtractReturnType<() => number>; // number
复制代码
经过上面两个例子能够看出,infer
声明的类型变量所在的位置,能够匹配出任何想要的值类型。spa
假设下面这种状况,同一个类型变量存在于多个位置,且每一个位置上的数据类型不一样,则会推断为 联合类型:code
type ExtractAllType<T> = T extends { x: infer U, y: infer U } ? U : T;
type T1 = ExtractAllType<{ x: string, y: number }>; // string | number
复制代码
这里的 ExtractAllType<T>
中 infer 格式中的属性是固定的 x 和 y,咱们能够优化一下,让它能够接收任意数量:htm
type ExtractAllType<T> = T extends { [k: string]: infer U } ? U : T;
type T1 = ExtractAllType<{ x: string, y: number, z: boolean }>; // string | number | boolean
复制代码
知道这个特性后,咱们再看上面提取数组中的类型的功能,实际上它还能够这么用:
type ExtractArrayItemType<T> = T extends (infer U)[] ? U : T;
type ItemTypes = ExtractArrayItemType<[string, number]>; // string | number
复制代码
这里实现了将 元组类型 转换成 联合类型。
重载声明的函数,始终获取最后一个声明,不过须要使用 typeof
功能转换下重置函数的格式:
declare function foo(x: string): number;
declare function foo(x: number): string;
declare function foo(x: string | number): string | number;
type 1 = ReturnType<typeof foo>; // string | number
复制代码