TS 中實現(xiàn) IsEqual 工具
最近刷體操題,很多場景都需要判斷兩個類型是否相同,那么如何優(yōu)雅地實現(xiàn)isEuqal<A, B>這樣一個工具類 呢?
很自然地想到了使用 extends,兩個類型互相 extends 的話那不就表示類型相同了么?
于是就有了第一種實現(xiàn)
原始方法
type IsEqual<A, B> = A extends B ? B extends A ? true : false : false
看起來是不是很容易?讓我們找?guī)讉€??測試一下
type IsEqual<A, B> = A extends B ? B extends A ? true : false : false
type A1 = IsEqual<string, string> // true
type A2 = IsEqual<string, number> // false
type A3 = IsEqual<{ name: string }, { name: string }> // true
type A4 = IsEqual<{ name: string}, { age: number }> // false
type A5 = IsEqual<{ name: string}, { name?: string }> // false
看起來效果也很好,那是不是這個實現(xiàn)就是完美了呢?
讓我們再看看其他的??
type A6 = IsEqual<true, boolean> // boolean
type A7 = IsEqual<1 | 2, 1> // boolean
對于這兩個??,我們期望得到的結果都是 false,但是實際結果卻都是 boolean,這就有點奇怪了,明明返回的結果應該是 true or false,怎么返回了一個 boolean?
事實上,boolean 類型在 ts 中和 true | false 是等價的,所以返回的類型是 boolean 其實就是返回了 true | false,也就是在 IsEqual 這個工具類里面兩個分支都走了。而為什么會走兩個分支呢?這又是因為泛型和 extends 兩者結合產(chǎn)生的 distributive conditional types這樣一種效應導致的。
既然第一種實現(xiàn)不太完美,那我們就該對癥下藥去解決第一個缺陷的地方,因為 extends 和泛型是這個實現(xiàn)里面必備的要素,但是又想避免由于這兩者結合所帶來的的 distributive conditional types 造成的影響。如何解決這種影響呢?也就是如何去消除 distributive conditional types 呢?ts官方告訴我們,給泛型套上一個[]就可以消除這種效應
于是,我們有了第二種實現(xiàn)
削微改進
type IsEqual<A, B> = [A] extends [B] ? [B] extends [A] ? true : false : false
當然,如果你嫌這樣的實現(xiàn)太丑陋的話可以簡化一下
type IsEqual<A, B> = [A, B] extends [B, A] ? true : false
這兩種實現(xiàn)是等價的
讓我們再去試試剛剛沒有通過的兩個??
type A7 = IsEqual<true, boolean> // false
type A8 = IsEqual<1 | 2, 1> // false
我們會發(fā)現(xiàn)這一回這倆??都可以完美通過了,是不是大功告成了呢?
(其實這個實現(xiàn)已經(jīng)可以幫助我們解決很大一部分的問題了)
但是很遺憾,還有些頑固??拒絕通過
type A9 = IsEqual<any, string> // true
type A10 = IsEqual< { name: string }, { readonly name: string }> // true
unbelivable, 為什么 any 和 string 是相同的類型,為什么 readonly 不能被區(qū)分出來?
在 ts中any可以賦給任何類型,任何類型也都可以賦給any,這就意味著any和任意類型之間都是assignable的,對于extends而言就是都可以互相extends,這也就是為什么A9類型是truereadonly不會改變assignable
對于以上這兩種頑固情況該怎么解決呢
經(jīng)過一通 Google,終于找到了一個相對完美的實現(xiàn)
Final version
type IsEqual<A, B> = (<T>() => T extends A ? 1 : 2) extends (<T1>() => T1 extends B ? 1 : 2) ? true : false
具體可參考 github.com/microsoft/T…[1]
再來看一下剛剛的頑固??
type A9 = IsEqual<any, string> // false
type A10 = IsEqual< { name: string }, { readonly name: string }> // false
最終版可以幫助你解決 Get Readonly Keys[2]
結語:
其實最終版的實現(xiàn)我還不是很懂,只知道是使用了 ts 內部的 isTypeIdenticalTo 實現(xiàn)的,如果有知道的大佬,請不吝賜教
原文地址
?? 看完三件事
非常棒的一篇Ts實用文章,
如果你覺得這篇內容對你挺有啟發(fā),不妨:
點個【在看】,或者分享轉發(fā),讓更多的人也能看到這篇內容
點擊↓面關注我們,一起學前端
長按↓面二維碼,添加鬼哥微信,一起學前端
