天天看點

TypeScript類型守衛、聯合類型、交叉類型

  類型保護是可執行運作時檢查的一種表達式,用于確定該類型在一定的範圍内。 換句話說,類型保護可以保證一個字元串是一個字元串,盡管它的值也可以是一個數值。類型保護與特性檢測并不是完全不同,其主要思想是嘗試檢測屬性、方法或原型,以确定如何處理值。目前主要有四種的方式來實作類型保護:

1、in 關鍵字:從下面代碼我門可以看出 可以判斷不同的屬性進行不同的業務。

2、typeof 關鍵字

<code>  typeof</code> 類型保護隻支援兩種形式:<code>typeof v === "typename"</code> 和 <code>typeof v !== typename</code>,<code>"typename"</code> 必須是 <code>"number"</code>, <code>"string"</code>, <code>"boolean"</code> 或 <code>"symbol"</code>。 但是 typescript 并不會阻止你與其它字元串比較,語言不會把那些表達式識别為類型保護。

3、instanceof 關鍵字

4、自定義類型保護的類型謂詞

  總結:簡言之,類型守衛就是加一層判斷,對于不同的判斷進行不同的業務處理。

1、聯合類型:聯合類型(union types)可以通過管道 ( | ) 将變量設定多種類型,指派時可以根據設定的類型來指派。

  注意:隻能指派指定的類型,如果指派其它類型就會報錯。

  建立聯合類型的文法格式如下:type1|type2|type3

  比如:可以用 | 來支援多種類型

  聯合類型通常與 <code>null</code> 或 <code>undefined</code> 一起使用。例如,這裡 <code>name</code> 的類型是 <code>string | undefined</code> 意味着可以将 <code>string</code> 或 <code>undefined</code> 的值傳遞給<code>sayhello</code> 函數。

  通過這個示例我們可以知道類型 a 和類型 b 聯合後的類型是同時接受 a 和 b 值的類型。此外,對于聯合類型來說,你可能會遇到以下的用法:

  以上示例中的 <code>1</code>、<code>2</code> 或 <code>'click'</code> 被稱為字面量類型,用來限制取值隻能是某幾個值中的一個。

2、可辨識聯合

  typescript 可辨識聯合(discriminated unions)類型,也稱為代數資料類型或标簽聯合類型。它包含 3 個要點:可辨識、聯合類型和類型守衛。

  這種類型的本質是結合聯合類型和字面量類型的一種類型保護方法。如果一個類型是多個類型的聯合類型,且多個類型含有一個公共屬性,那麼就可以利用這個公共屬性,來建立不同的類型保護區塊。

(1)可辨識:可辨識要求聯合類型中的每個元素都含有一個單例類型屬性,比如:

  在上述代碼中,我們分别定義了 <code>motorcycle</code>、 <code>car</code> 和 <code>truck</code> 三個接口,在這些接口中都包含一個 <code>vtype</code> 屬性,該屬性被稱為可辨識的屬性,而其它的屬性隻跟特性的接口相關。

(2)聯合類型:基于前面定義了三個接口,我們可以建立一個 <code>vehicle</code> 聯合類型:

  現在我們就可以開始使用 <code>vehicle</code> 聯合類型,對于 <code>vehicle</code> 類型的變量,它可以表示不同類型的車輛。

(3)類型守衛:下面我們來定義一個 <code>evaluateprice</code> 方法,該方法用于根據車輛的類型、容量和評估因子來計算價格,具體實作如下:

  原因是在 motorcycle 接口中,并不存在 <code>capacity</code> 屬性,而對于 car 接口來說,它也不存在 <code>capacity</code> 屬性。那麼,現在我們應該如何解決以上問題呢?這時,我們可以使用類型守衛。下面我們來重構一下前面定義的 <code>evaluateprice</code> 方法,重構後的代碼如下:

  在以上代碼中,我們使用 <code>switch</code> 和 <code>case</code> 運算符來實作類型守衛,進而確定在 <code>evaluateprice</code> 方法中,我們可以安全地通路 <code>vehicle</code> 對象中的所包含的屬性,來正确的計算該車輛類型所對應的價格。

  是以從這裡也可以看出所謂類型守衛就是確定所使用的類型均可以正常使用,進而針對不同類型,使用不同的業務處理。

  在 typescript 中交叉類型是将多個類型合并為一個類型。通過 <code>&amp;</code> 運算符可以将現有的多種類型疊加到一起成為一種類型,它包含了所需的所有類型的特性。

  在上面代碼中我們先定義了 <code>partialpointx</code> 類型,接着使用 <code>&amp;</code> 運算符建立一個新的 <code>point</code> 類型,表示一個含有 x 和 y 坐标的點,然後定義了一個 <code>point</code> 類型的變量并初始化。

1、同名基礎類型屬性的合并

  那麼問題來了,假設在合并多個類型的過程中,剛好出現某些類型存在相同的成員,但對應的類型又不一緻,比如:

  在上面的代碼中,接口 x 和接口 y 都含有一個相同的成員 c,但它們的類型不一緻。對于這種情況,此時 xy 類型或 yx 類型中成員 c 的類型是不是可以是 <code>string</code> 或 <code>number</code> 類型呢?不是的,結論是 never。

  為什麼接口 x 和接口 y 混入後,成員 c 的類型會變成 <code>never</code> 呢?這是因為混入後成員 c 的類型為 <code>string &amp; number</code>,即成員 c 的類型既可以是 <code>string</code> 類型又可以是 <code>number</code> 類型。很明顯這種類型是不存在的,是以混入後成員 c 的類型為 <code>never</code>。

2、同名非基礎類型屬性的合并

  在上面示例中,剛好接口 x 和接口 y 中内部成員 c 的類型都是基本資料類型,那麼如果是非基本資料類型的話,又會是什麼情形。我們來看個具體的例子:

  以上代碼可以成功運作,且 abc 就為上述結果。由此可知:在混入多個類型時,若存在相同的成員,且成員類型為非基本資料類型,那麼是可以成功合并。

  總結:

(1)同名基礎類型屬性合并:string &amp; number,這樣的值不存在,是以是 never;

(2)同名非基礎類型屬性合并:比如 { a: string } &amp; { b: number },可以成功合并為 { a: string, b: number }。