---
# System prepended metadata

title: Untitled

---

【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折!