【TypeScript 小教室 03】
接續上一篇內容:[什麼是型別防衛敘述 (type guard)](https://hackmd.io/@flag23311033/rJDpwuGDt)?
要解釋型別防衛敘述,我們要先從 TypeScript 提供的一個功能──型別聯集 (type union) 說起。
* * *
若把 TypeScript 的型別保護機制想像成一道光譜, 其中一端就是絕對自由的 any 型別, 而另一端則是只准使用單一型別的嚴格型別註記。不過在這兩個極端之間, TypeScript 提供了所謂的型別聯集, 允許你用一個型別來接納多種型別。底下的範例便定義了一個可傳回不同資料型別的函式, 並使用型別聯集為其進行註記:
function calculateTax(amount: number, format: boolean): string | number
calculateTax() 函式的傳回值是 string 與 number 這兩種型別的聯集, 代表它可以是 string 或者 number...
要特別注意的是, TypeScript 會將型別聯集視為一個獨立的型別, 而它可以呼叫的方法就是其中所有型別的交集 ( 意即, 只有每個型別都共同具備的方法, 才能在型別聯集使用)。這代表即使 calculateTax() 傳回 number, 函式的傳回值以及 taxNumber 變數的推論型別都是『 string | number』 而非只是 number。
---摘錄至 《[TypeScript 邁向專家之路](https://www.books.com.tw/products/0010906604)》Ch.7
* * *
換句話說,就算 calculateTax() 函式的傳回值是 string 或 number,這個值實際上會變成 string | number 聯集型別。而當我們想要把這個值重新當成 string 或 number 型別操作時,可以使用型別斷言 (type assertion):
let taxNumber = calculateTax(100, false) as number;
let taxString = calculateTax(100, true) as string;
問題在於,型別斷言並不會做型別轉換,它只是在告訴 TypeScript 編譯器:聽好,老子說這是 number 就是 number!但這樣不能保證值本身的型別真的和你認定的一樣。要是你呼叫值的某個方法,值的型別卻搞錯了,這種錯誤就會等到實際執行才引爆。
在這種時候,型別防衛敘述就派上用場了:
* * *
型別斷言固然方便, 但無法確保值本身的型別符合斷言指定的型別。為了確保操作上的安全, 我們可利用條件敘述結合 typeof 關鍵字來檢測一個值是否為特定基本型別, 並藉此將之限縮到該型別。這種機制稱為型別防衛敘述:
let taxValue = calculateTax(100, false);
// 型別防衛敘述
if (typeof taxValue === "number") {
console.log(`Number Value: ${taxValue.toFixed(2)}`);
} else {
console.log(`String Value: ${taxValue.charAt(0)}`);
}
--- 摘錄至《[TypeScript 邁向專家之路](https://www.books.com.tw/products/0010906604)》Ch.7
* * *
TypeScript 編譯器會知道,if 區塊中只有 taxValue 為 number 型別時才能執行,所以這區塊內的 taxValue 會自動被「限縮」為 number 型別。反之,else 區塊內的 taxValue 一定只會是 string,故此區塊的值會變成 string 型別。
藉由型別防衛敘述,我們就可以在程式中保留 JavaScript 能對變數賦予多種型別的彈性、但在操作時仍然確保其型別安全,減少在執行階段引發非預期錯誤的機會。
TypeScript 的型別防衛敘述並不限於 if...else,它同樣適用於 switch...case。而且 TypeScript 提供的型別機制更包括但不限於以下功能:
‧unknown 與 never 型別
‧用編譯器選項 strictNullChecks 禁止將 null 與 undefined 指派給值
‧非 null 值斷言 (non-null assertion)
‧明確賦值斷言 (definitive assignment assertion)
‧函式的型別多載 (type overloading)
‧型別別名 (type alias)
‧字面值型別 (literal value type)
‧型別交集 (type intersections)
我們甚至還沒談到和泛型 (generic type) 有關的部分哩!而你都可在書中找到以上這些型別機制的詳盡介紹與範例。
[想了解更多內容?]
博客來79折優惠中(https://pse.is/3sv8j6)
與《完全自學!Go 語言 (Golang) 實戰聖經》合購享75折!