Skip to content

建立 2026-09-15 更新 2026-09-15

型別縮小

型別縮小(Narrowing)是 TypeScript 根據程式碼裡的判斷式(iftypeofin 等),自動把一個較廣的型別(例如 union)在某個範圍內「縮小」成更精確的型別。這是讓 Union 型別 用起來安全又方便的關鍵機制。

typeof:縮小基本型別

function formatValue(value: string | number) {
  if (typeof value === "string") {
    return value.toUpperCase() // 這裡 TS 知道 value 是 string
  }
  return value.toFixed(2)      // 這裡自動剩下 number
}

typeof value === "string" 這個判斷式本身沒有任何特殊語法,但 TypeScript 會分析程式流程:在 if 區塊裡,value 一定是 string;離開這個區塊,剩下的可能性只有 number

in:縮小物件形狀

interface Cat { meow(): void }
interface Dog { bark(): void }

function makeSound(animal: Cat | Dog) {
  if ("meow" in animal) {
    animal.meow() // 縮小成 Cat
  } else {
    animal.bark()  // 縮小成 Dog
  }
}

in 檢查物件是否有某個屬性/方法名稱,適合用在兩個型別沒有共同的可判斷欄位、但成員名稱不同的情況。

Discriminated Union:最常見的實務寫法

type LoadingState = { status: "loading" }
type SuccessState = { status: "success"; data: string[] }
type ErrorState = { status: "error"; message: string }

type State = LoadingState | SuccessState | ErrorState

function render(state: State) {
  switch (state.status) {
    case "loading":
      return "Loading..."
    case "success":
      return `Got ${state.data.length} items` // 這裡自動縮小成 SuccessState
    case "error":
      return `Error: ${state.message}`         // 自動縮小成 ErrorState
  }
}

每個型別都有一個共同、但值不同的欄位(這裡是 status,稱為判別欄位/discriminant),switchif 判斷這個欄位後,TypeScript 就能精準縮小到對應的那個型別,抓到「存取到不存在屬性」這種錯誤。這是描述「非同步狀態」「表單驗證結果」這類多種可能狀態時最推薦的寫法。

相關資源

型別縮小是「懂 union 卻不知道怎麼安全使用」最常卡關的地方,目前沒有找到品質夠好、頻道夠可信的獨立教學影片可以嵌入;官方 Handbook 的 Narrowing 一章把每種寫法搭配範例講得很完整,建議直接讀這篇,或在 影音教學 的長篇課程裡找 narrowing/union 段落對照。