類型推斷 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
複製代碼