大家好蛾坯,我蘇先生光酣,一名熱愛(ài)鉆研、樂(lè)于分享的前端切圖仔
github與好文
前言
上一節(jié)倘零,我們通過(guò)12個(gè)內(nèi)置工具類(lèi)型初步感受了下類(lèi)型體操是個(gè)啥:通過(guò)對(duì)一個(gè)已知類(lèi)型編程生成一個(gè)新的類(lèi)型
按照本小冊(cè)的規(guī)劃唱遭,還差87個(gè)...
本節(jié),我們?cè)黾酉码y度呈驶,一起來(lái)實(shí)現(xiàn)下Merge拷泽、Diff、Flip
提示
對(duì)于語(yǔ)法層面的知識(shí)點(diǎn)本系列(類(lèi)型體操開(kāi)頭的標(biāo)題)不會(huì)展開(kāi)說(shuō)明哈袖瞻,可以自行搜索學(xué)習(xí)其他大佬的優(yōu)質(zhì)文章或者等我后續(xù)更新補(bǔ)充
Merge
功能
合并兩個(gè)已知類(lèi)型司致,對(duì)于同名的key,向前進(jìn)行覆蓋聋迎,最后返回一個(gè)新類(lèi)型
實(shí)現(xiàn)
它接收兩個(gè)泛型參數(shù):T脂矫、U
type Merge<T,U>
我們要判斷的是key是否重復(fù),因此我們必須拿到每一個(gè)key值霉晕,這在TypeScript中可以通過(guò)keyof來(lái)獲取庭再,并且它返回的是一個(gè)聯(lián)合類(lèi)型
type KOfT = keyof T
type KOfU = keyof U
然后,我們需要將KOfT和KOfU進(jìn)行合并牺堰,生成一個(gè)具有不重復(fù)key的聯(lián)合類(lèi)型
type UniKey = KOfT | KOfU
我們使用|生成一個(gè)新的聯(lián)合類(lèi)型拄轻,在這一過(guò)程中,TypeScript會(huì)自動(dòng)將重名的key進(jìn)行剔除伟葫,如圖所示
接著哺眯,我們需要拿到T中的每一個(gè)key到U中判斷是否存在,因此我們還需要使用in關(guān)鍵字進(jìn)行遍歷
type UniKey = K in KOfT | KOfU
然后扒俯,我們使用extends關(guān)鍵字來(lái)構(gòu)建條件類(lèi)型奶卓,并分情況討論:
1-K是KOfU的子類(lèi)型,則直接使用KOfU的key作為合并后的結(jié)果
2-如果不是撼玄,則判斷是否是KOfT的子類(lèi)型夺姑,不是則使用never進(jìn)行過(guò)濾
K extends KOfU ? S[K] : K extends KOfT ? T[K] : never
最后我們只需要借助映射類(lèi)型進(jìn)行下組裝就可以啦:
type Merge<T, U> = {
[K in keyof T | keyof U]: K extends keyof U
? U[K]
: K extends keyof T
? T[K]
: never;
};
Diff
功能
找出兩個(gè)對(duì)象類(lèi)型的差異,并將差異部分組成一個(gè)新的類(lèi)型返回
實(shí)現(xiàn)
它接收兩個(gè)泛型參數(shù)
type Diff<T,U>
這兩個(gè)泛形應(yīng)該是對(duì)象類(lèi)型掌猛,因此我們需要對(duì)其進(jìn)行約束
type Diff<T extends object,U extends object>
同樣的盏浙,我們要先將獲取到兩個(gè)類(lèi)型的所有的key眉睹,然后才能考慮進(jìn)行比較判斷,關(guān)于key的獲取废膘,按照前文的實(shí)現(xiàn)竹海,我們可以使用keyof先將其轉(zhuǎn)換為聯(lián)合類(lèi)型再通過(guò)|來(lái)得到,但是這里我們換一種實(shí)現(xiàn)方式丐黄,我們先對(duì)接口進(jìn)行合并然后再keyof取值
type UniKey = keyof (T&U)
接著我們拿到新類(lèi)型UniKey中的每一個(gè)key斋配,即K
K in UniKey
此時(shí),如果我們能拿到兩個(gè)類(lèi)型共有的部分灌闺,那就可以使用在手寫(xiě)12個(gè)TypeScript內(nèi)置工具類(lèi)型中實(shí)現(xiàn)的Exclude工具類(lèi)型進(jìn)行排除:
1-獲取類(lèi)型的公共部分
type Com = keyof (T|U)
2-使用Exclude工具類(lèi)型將key排除
type Excluded = Exclude<K,Com>
接著我們將其斷言為新的類(lèi)型Excluded
K in UniKey as Excluded
至于key對(duì)應(yīng)的原泛型中的類(lèi)型艰争,我們使用索引訪問(wèn)類(lèi)型直接從接口合并結(jié)果中取就好了
(T&U)[K]
最后,老規(guī)矩桂对,我們通過(guò)映射類(lèi)型進(jìn)行下組裝:
type Diff<T extends object,U extends object> = {
[K in keyof (T & U) as Exclude<K,keyof (T|U)>]:(T&U)[K]
}
推廣時(shí)間:
我本來(lái)一直在推我的約定式路由庫(kù)甩卓,不過(guò)目前看來(lái)收效甚微。所以我這里就不再花大篇幅去寫(xiě)了蕉斜,就簡(jiǎn)單提一嘴
Flip
功能
交換一個(gè)對(duì)象類(lèi)型的key和value逾柿,并返回一個(gè)新的類(lèi)型
實(shí)現(xiàn)
它接受一個(gè)泛型類(lèi)型T
type Flip<T>
由于對(duì)象類(lèi)型的key只能是基本類(lèi)型,但是其value卻可以是任意類(lèi)型宅此,那就意味著鹿寻,當(dāng)我們使用索引類(lèi)型T[K]來(lái)取value作為新的key時(shí),將會(huì)有報(bào)錯(cuò)風(fēng)險(xiǎn)诽凌,因此,我們對(duì)key進(jìn)行下約束
type Flip<T extends Record<string|number|boolean,any>>
接著我們獲取到每一個(gè)key
K in keyof T
然后對(duì)其進(jìn)行斷言
type NewKey = K as T[K]
最后使用映射進(jìn)行組裝坦敌,并將K作為value即可
type Flip<T extends Record<string|number|boolean,any>> = {
[K in keyof T K as T[K]] : K
}
關(guān)于“理想很豐滿(mǎn)侣诵,現(xiàn)實(shí)很骨感”這句話(huà),許是對(duì)的S健6潘场!上文的寫(xiě)法會(huì)被TypeScript推斷出錯(cuò)誤
[圖片上傳失敗...(image-c94871-1686489361019)]
按照錯(cuò)誤提示蘸炸,我們將boolean修改為symbol后的最終代碼實(shí)現(xiàn)如下
type Flip<T extends Record<string|number|symbol,any>> = {
[K in keyof T as T[K]] : K
}
如果本文對(duì)您有用躬络,希望能得到您的點(diǎn)贊和收藏