TypeScript 的條件類型使用示例詳解
TypeScript 的條件類型使用方式
我們可以使用 TypeScript 中的條件類型來根據(jù)邏輯定義某些類型,就像是在編寫代碼那樣。
它采用的語(yǔ)法和我們?cè)?JavaScript 中熟悉的三元運(yùn)算符很像:condition ? ifConditionTrue : ifConditionFalse。
我們來看看他是怎么工作的。
假設(shè)我們有一個(gè)值,這個(gè)值可以表示用戶的出生日期或者年齡。
- 如果是出生日期,那他的類型應(yīng)該是 string。
- 如果是年齡,那他的類型是 number。
我們來定義這三種類型。
type Dob = string; type Age = number; type UserAgeInformation<T> = T extends number ? number : string;
Dob 和 Age 不需要多解釋,我們來解釋一下 UserAgeInformation。
它接受一個(gè)泛型,可以是任何類型。如果 T extends number 為 true,就意味著傳入的類型是 number 類型,我們就把 UserAgeInformation 設(shè)置為 number 類型。否則的話就設(shè)置為 string 類型。
我們?cè)谑褂玫臅r(shí)候可以這樣:
let userAge:UserAgeInformation<Age> = 100; let userDob:UserAgeInformation<Dob> = '12/12/1945';
條件類型和 keyof 組合
除了上面介紹的用法,我們還可以通過檢查是否擴(kuò)展了一個(gè)對(duì)象來更進(jìn)一步。比如,假設(shè)我們的客戶有兩種類型:Horse 和 User。
兩種類型的客戶都有 age、name 兩個(gè)字段。
- User 類型的客戶還有一個(gè) address 字段,它表示了詳細(xì)的地址。
- Horse 類型的客戶有 location 兩個(gè)字段,它只是表示一個(gè)大概的位置。
我們來定義這幾種類型:
type User = { age: number, name: string, address: string } type Horse = { age: number, name: string } type UserAddress = { addressLine1: string, city: string, country: string, } type HorseAddress = { location: 'farm' | 'savanna' | 'field' | 'other' }
在未來,我們還可能會(huì)有其他類型的客戶,所以我們可以通過檢查 T 是否具有 address 屬性,如果有,我們使用 UserAddress 類型,否則使用 HorseAddress 類型。
type AddressComponents<T> = T extends { address: string } ? UserAddress : HorseAddress let userAddress:AddressComponents<User> = { addressLine1: "123 Fake Street", city: "Boston", country: "USA" } let horseAddress:AddressComponents<Horse> = { location: 'farm' }
T extends { address: string } 的含義是檢查 T 是否具有 address 屬性。
在條件返回中使用 T
在三元表達(dá)式的條件返回中,我們也可以使用 T。
比如下面的例子:
type User = { age: number, name: string, address: string } type Horse = { age: number, name: string } type UserType<T> = T extends { address: string } ? T : Horse let myUser: UserType<User> = { age: 104, name: "John Doe", address: "123 Fake Street" }
T 被定義為 User,當(dāng)我們調(diào)用 UserType 時(shí),myUser 的類型就是 User,并且需要具有這種類型中所定義的字段。
在類型輸出中使用 T 時(shí)的聯(lián)合類型
如果我們?cè)谶@里傳遞一個(gè)聯(lián)合類型:
type UserType<T> = T extends { address: string } ? T : string let myUser: UserType<User | Horse> = { age: 104, name: "John Doe", address: "123 Fake Street" }
myUser 的類型會(huì)變成是 User|string,因?yàn)?User 通過了條件檢測(cè),但是 Horse 沒有通過,所以它的類型是字符串。
如果我們以某種方式修改 T,比如把它設(shè)置為數(shù)組。所有 T 的值都會(huì)被單獨(dú)修改。
type User = { age?: number, name: string, address?: string } type Horse = { age?: number, name: string } // 如果 T 包含類型是 string 的 name 屬性,就會(huì)返回 T[] type UserType<T> = T extends { name: string } ? T[] : never; // myUser 的類型是 User[]|Horse[],因?yàn)?User 和 Horse 都具有 name 屬性 let myUser:UserType<User | Horse> = [{ name: "John" }, { name: "Horse" }]
在這里我們已經(jīng)簡(jiǎn)化了 User 和 Horse,它們只留下了必須需要的 name 字段。在條件類型中,兩種類型都包含了 name。
所以兩者都會(huì)返回 true,并且返回的類型是 T[],由于兩者都返回 true,所以 myUser 的類型是 User[]|Horse[],所以我們可以簡(jiǎn)單地提供一個(gè)包含 name 屬性的對(duì)象數(shù)組。
這種行為通常很好,但是在某些情況下,我們希望返回一個(gè)數(shù)組。
在這種情況下,如果我們想避免這樣分布類型,可以在 周圍添加 { name: string }。
type User = { age?: number, name: string, address?: string } type Horse = { age?: number, name: string } // 我們避免分布類型,因?yàn)?T 和 { name: string} 都在方括號(hào)中 type UserType<T> = [T] extends [{ name: string }] ? T[] : never; // 這樣現(xiàn)在的類型不同了,它是 (User|Horse)[] let myUser:UserType<User | Horse> = [{ name: "John" }, { name: "Horse" }]
通過使用方括號(hào),我們的類型已經(jīng)轉(zhuǎn)為 (User|Horse)[],而不是 User[]|Horse[]。
這在某些特殊的場(chǎng)景中很有用。但是條件類型會(huì)增加復(fù)雜性,不可以濫用。
使用條件類型推斷類型
我們也可以在使用條件時(shí)使用 infer 關(guān)鍵字。
假設(shè)我們有兩種類型,一種用于數(shù)字?jǐn)?shù)組,另一種用于字符串?dāng)?shù)組。
在這個(gè)例子中,infer 將會(huì)推斷數(shù)組中每個(gè)項(xiàng)目的類型,并返回正確的類型:
type StringArray = string[] type NumberArray = number[] type MixedArray = number[] | string[] type ArrayType<T> = T extends Array<infer Item> ? Item: never // 因?yàn)?NumberArray 中項(xiàng)目的類型是 number,所以 myItem1 是 number 類型 let myItem1: ArrayType<NumberArray> = 45 // 因?yàn)?StringArray 中項(xiàng)目的類型是 string,所以 myItem2 是 string 類型 let myItem2: ArrayType<StringArray> = 'string' // 因?yàn)?MixedArray 中項(xiàng)目的類型是 number|string,所以 myItem3 是 number|string 類型 let myItem3: ArrayType<MixedArray> = 'string'
我們?cè)跅l件類型中定義了一個(gè)新的參數(shù) Item,它是 extends Array 中的子項(xiàng) T。
但是我們必須傳入數(shù)組,它才會(huì)有效,因?yàn)槲覀兪褂玫氖?Array。
如果 T 不是數(shù)組,那么 ArrayType 的類型將會(huì)是 never。
總結(jié)
如果你剛接觸到 TypeScript 的條件類型,你可能會(huì)覺得很疑惑。但是它解決了某些特定情況下編寫類型比較復(fù)雜的一種解決方式。
如果你在某個(gè)項(xiàng)目中看到它,或者簡(jiǎn)化你想你的項(xiàng)目代碼,它或許很有用。
以上就是TypeScript 的條件類型使用詳解 的詳細(xì)內(nèi)容,更多關(guān)于TypeScript 條件類型的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
umi插件開發(fā)仿dumi項(xiàng)目自動(dòng)生成導(dǎo)航欄實(shí)現(xiàn)詳解
這篇文章主要為大家介紹了umi插件開發(fā)仿dumi項(xiàng)目自動(dòng)生成導(dǎo)航欄實(shí)現(xiàn)詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-01-01微信小程序 詳解下拉加載與上拉刷新實(shí)現(xiàn)方法
這篇文章主要介紹了微信小程序 詳解下拉加載與上拉刷新實(shí)現(xiàn)方法的相關(guān)資料,這里介紹了兩種實(shí)現(xiàn)方法,需要的朋友可以參考下2017-01-01