當前位置:
首頁 > 知識 > TypeScript基礎之高級類型的可辨識聯合(Discriminated Unions)

TypeScript基礎之高級類型的可辨識聯合(Discriminated Unions)

高級類型

可辨識聯合(Discriminated Unions)

你可以合併單例類型,聯合類型,類型保護和類型別名來創建一個叫做 可辨識聯合的高級模式,它也稱做 標籤聯合或 代數數據類型。 可辨識聯合在函數式編程很有用處。 一些語言會自動地為你辨識聯合;而TypeScript則基於已有的JavaScript模式。 它具有3個要素:

1. 具有普通的單例類型屬性— 可辨識的特徵。

2. 一個類型別名包含了那些類型的聯合— 聯合。

3. 此屬性上的類型保護。

interface Interface1 {
kind: "interface1",
property1: number,
}
interface Interface2 {
kind: "interface2",
property2: number,
property3: number,
}
interface Interface3 {
kind: "interface3",
property4: number,
property5: number,
}

首先我們聲明了將要聯合的介面。 每個介面都有 kind屬性但有不同的字元串字面量類型。 kind屬性稱做 可辨識的特徵或 標籤。 其它的屬性則特定於各個介面。 注意,目前各個介面間是沒有聯繫的。 下面我們把它們聯合到一起:

type Type = Interface1 | Interface2 | Interface3;

現在我們使用可辨識聯合:

function getType(i: Type) {
switch (i.kind) {
case "interface1":
return i.property1 * i .property1;
case "interface2":
return i.property2 * i.property3;
case "interface3":
return i.property4 * i.property5;
}
}

完整性檢查

當沒有涵蓋所有可辨識聯合的變化時,我們想讓編譯器可以通知我們。 比如,如果我們添加了Interface4到Type,我們同時還需要更新 area:

interface Interface4 {
kind: "interface4",
property6: number,
}
type Type = Interface1 | Interface2 | Interface3 | Interface4;
function getType(i: Type) {
switch (i.kind) {
case "interface1":
return i.property1 * i .property1;
case "interface2":
return i.property2 * i.property3;
case "interface3":
return i.property4 * i.property5;
}
}

有兩種方式可以實現。 首先是啟用 --strictNullChecks並且指定一個返回值類型:

function getType(i: Type): number { // error: returns number | undefined
switch (i.kind) {
case "interface1":
return i.property1 * i .property1;
case "interface2":
return i.property2 * i.property3;
case "interface3":
return i.property4 * i.property5;
}
}

因為 switch沒有包涵所有情況,所以TypeScript認為這個函數有時候會返回 undefined。 如果你明確地指定了返回值類型為 number,那麼你會看到一個錯誤,因為實際上返回值的類型為 number | undefined。 然而,這種方法存在些微妙之處且 --strictNullChecks對舊代碼支持不好。第二種方法使用 never類型,編譯器用它來進行完整性檢查:

function assertNever(x: never): never {
throw new Error("Unexpected object: " + x);
}
function getType(i: Type): number { // error: returns number | undefined
switch (i.kind) {
case "interface1":
return i.property1 * i .property1;
case "interface2":
return i.property2 * i.property3;
case "interface3":
return i.property4 * i.property5;
default:
return assertNever(i); // error here if there are missing cases
}
}

這裡, assertNever檢查 s是否為 never類型—即為除去所有可能情況後剩下的類型。 如果你忘記了某個case,那麼 s將具有一個真實的類型並且你會得到一個錯誤。 這種方式需要你定義一個額外的函數,但是在你忘記某個case的時候也更加明顯。**Tips**

上面的代碼是根據官網的邏輯寫的,奇怪的是最後一步居然在編譯的時候報錯了。報錯信息如下

$ tsc src/advanced_types_4.ts
src/advanced_types_4.ts:38:26 - error TS2345: Argument of type "Interface4" is not assignable to parameter of type "never".
38 return assertNever(i); // error here if there are missing cases
~

TypeScript基礎之高級類型的可辨識聯合(Discriminated Unions)

喜歡這篇文章嗎?立刻分享出去讓更多人知道吧!

本站內容充實豐富,博大精深,小編精選每日熱門資訊,隨時更新,點擊「搶先收到最新資訊」瀏覽吧!


請您繼續閱讀更多來自 程序員小新人學習 的精彩文章:

DRF與xadmin框架基本搭建
Discuz全版本任意文件刪除漏洞

TAG:程序員小新人學習 |