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
~
※DRF與xadmin框架基本搭建
※Discuz全版本任意文件刪除漏洞
TAG:程序員小新人學習 |