新聞中心
type T0 = string[];
type T1 = () => string;
要實現(xiàn)上述的功能,我們可以使用 TypeScript 提供的類型模式匹配技術(shù) —— 條件類型 + infer。條件類型允許我們檢測兩種類型之間的關(guān)系,通過條件類型我們就可以判斷兩種類型是否相兼容。而 infer 用于聲明類型變量,以存儲在模式匹配過程中所捕獲的類型。

創(chuàng)新互聯(lián)建站主要從事做網(wǎng)站、網(wǎng)站設(shè)計、網(wǎng)頁設(shè)計、企業(yè)做網(wǎng)站、公司建網(wǎng)站等業(yè)務(wù)。立足成都服務(wù)上栗,十余年網(wǎng)站建設(shè)經(jīng)驗,價格優(yōu)惠、服務(wù)專業(yè),歡迎來電咨詢建站服務(wù):18982081108
下面我們來看一下如何捕獲 T0 數(shù)組類型中元素的類型:
type UnpackedArray= T extends (infer U)[] ? U : T
type U0 = UnpackedArray// string
在以上代碼中,T extends (infer U)[] ? U : T 是條件類型的語法,而 extends 子句中的 infer U 引入了一個新的類型變量 U,用于存儲被推斷的類型。
為了便于大家的理解,我們來演示一下 UnpackedArray 工具類型的執(zhí)行流程。
type U0 = UnpackedArray
// T => T0: string[]
type UnpackedArray= string[] extends (infer U)[] ? U : string[]
// string[] extends (infer U)[] 模式匹配成功
// U => string
需要注意的是,infer 只能在條件類型的 extends 子句中使用,同時 infer 聲明的類型變量只在條件類型的 true 分支中可用。
type Wrong1= T[0] // Error
type Wrong2= (infer U)[] extends T ? U : T // Error
type Wrong3= T extends (infer U)[] ? T : U // Error
了解完這些知識之后,我們來看一下如何獲取 T1 函數(shù)類型的返回值類型:
type UnpackedFn= T extends (...args: any[]) => infer U ? U : T;
type U1 = UnpackedFn; // string
看完 UnpackedFn 工具類型的實現(xiàn),是不是覺得挺簡單的。當(dāng)遇到函數(shù)重載的場景,TypeScript 將使用最后一個調(diào)用簽名進行類型推斷:
declare function foo(x: string): number;
declare function foo(x: number): string;
declare function foo(x: string | number): string | number;
type UnpackedFn= T extends (...args: any[]) => infer U ? U : T;
type U2 = UnpackedFn; // string | number
如果你對 TypeScript 的條件類型還不了解的話,建議觀看 “用了 TS 條件類型,同事直呼 YYDS” 這篇文章。在該篇文章中,我們介紹了條件鏈,利用條件鏈我們可以實現(xiàn)功能更加強大的 Unpacked 工具類型。
type Unpacked=
T extends (infer U)[] ? U :
T extends (...args: any[]) => infer U ? U :
T extends Promise? U :
T;
type T0 = Unpacked; // string
type T1 = Unpacked; // string
type T2 = Unpacked<() => string>; // string
type T3 = Unpacked>; // string
type T4 = Unpacked[]>; // Promise
type T5 = Unpacked[]>>; // string
在以上代碼中,Unpacked 工具類型利用了條件類型和條件鏈,輕松實現(xiàn)了推斷出數(shù)組類型中元素的類型、函數(shù)類型返回值的類型和 Promise 類型中返回值的類型的功能。
其實,利用條件類型和 infer,我們還可以推斷出對象類型中鍵的類型。接下來,我們來舉個具體的例子:
type User = {
id: number;
name: string;
}
type PropertyType = T extends { id: infer U, name: infer R } ? [U, R] : T
type U3 = PropertyType // [number, string] 在 PropertyType 工具類型中,我們通過 infer 聲明了兩個類型變量 U 和 R,分別表示對象類型中 id 和 name 屬性的類型。若類型匹配,我們就會以元組的形式返回 id 和 name 屬性的類型。
那么現(xiàn)在問題來了,在 PropertyType 工具類型中,如果只聲明一個類型變量 U,那結(jié)果又會是怎樣呢?下面我們來驗證一下:
type PropertyType= T extends { id: infer U, name: infer U } ? U : T
type U4 = PropertyType// string | number
由以上代碼可知,U4 類型返回的是 string 和 number 類型組合成的聯(lián)合類型。為什么會返回這樣的結(jié)果呢?這是因為在協(xié)變位置上,若同一個類型變量存在多個候選者,則最終的類型將被推斷為聯(lián)合類型。
然而,在逆變位置上,若同一個類型變量存在多個候選者,則最終的類型將被推斷為交叉類型。同樣,我們來實際驗證一下:
type Bar= T extends { a: (x: infer U) => void, b: (x: infer U) => void } ? U : never;
type U5 = Bar<{ a: (x: string) => void, b: (x: number) => void }>; // string & number
在以上代碼中,U5 類型返回的是 string 和 number 類型組合成的交叉類型,即最終的類型是 never 類型。
看完本文之后,相信你已經(jīng)了解條件類型和 infer 的作用了。那么你能看懂 UnionToIntersection 這個工具類型的具體實現(xiàn)么?
type UnionToIntersection = (
U extends any ? (arg: U) => void : never
) extends (arg: infer R) => void
? R
: never
網(wǎng)頁標(biāo)題:學(xué)會TSinfer,寫起泛型真香!
轉(zhuǎn)載注明:http://m.fisionsoft.com.cn/article/djdhseo.html


咨詢
建站咨詢
