換個視角來看TypeScript中的交叉運算

Qing發表於2023-03-03

引文

相信只要接觸過ts的同學就有了解交叉型別這兩個概念,以前我對交叉型別感到非常疑惑,明明叫交叉型別,為何對物件型別使用了交叉運算後型別反而會進行屬性的合併?不知道大家有沒有和我一樣的困惑。這篇文章我會分享我最近感悟到的用不同視角來解釋出現上述問題的原因,如有錯誤,懇請指正。

交叉運算

在ts中,使用&這個符號來對兩個型別進行交叉運算,下面舉幾個小例子來開始講解。

例一

type A = number & string    // never

例二

type A = 1 & number                // 1
type B = "hello" & string          // "hello"

例三

type A1 = {a: number}
type A2 = {aa: string}

這裡的例子正是我在引文中提到的情況,按照交叉這個字面意思來理解,{a: number}{aa: string}兩個好像也沒有什麼交集,按照例一的思路來思考,結果應該是never,為何結果是{a: number, aa: string}

首先來思考一個問題,假設有這麼幾個物件:

  • {a: 1, b: 2}
  • {aa: "11", bb: "22"}
  • {a: 1, b: 2, aa: "11", bb: "22"}

這幾個物件分別賦值給型別為A1、A2、A的變數,哪個型別的變數在被賦值的時候有比較大的可能會出現錯誤?

相信大家能夠很容易的猜到答案,那就是上面的這三個物件在給型別為A的變數賦值的時候前兩個物件都會報錯,只有最後一個物件是符合型別要求的。

上述中的A1、A2型別,A1型別的變數只需要值中有屬性名為a,屬性值型別為number的屬性即可滿足,而A2型別的變數只需要值中有屬性名為aa,屬性值型別為string的屬性即可滿足,而A型別的變數對值的要求是必須要同時有a和aa這兩個屬性。

那麼符合A1、A2、A型別的值各有幾個?可以歸類下

  • 符合A1型別的值:{a: 1, b: 2}、{a: 1, b: 2, aa: "11", bb: "22"}
  • 符合A2型別的值:{aa: "11", bb: "22"}、{a: 1, b: 2, aa: "11", bb: "22"}
  • 符合A型別的值:{a: 1, b: 2, aa: "11", bb: "22"}

可以看到在A1 & A2後得到的A型別,其值相對於A1和A2這兩個型別對應的值的範圍是變小的,這也符合交叉運算的結果趨勢。

我們對數學中的交併集運算有著很深的印象,但是數學上交併集運算作用的物件卻是具體的數值,如果把這種思想轉換到ts型別上來,其實不太合適,而是應該把這種思想作用到ts型別所對應的值上。

現在用這種思路去思考例一和例二,也是能夠走通的。

交叉運算在處理物件型別的時候,交叉過後屬性反而增多,初看覺得不對勁,但轉換角度細想或許能發現其中的道理。

總結:交叉運算會導致能夠賦值給結果型別的變數範圍變小,這個型別的限制也會變得更嚴格。

相關文章