Article
Is Operator in Typescript
最近在寫 ts 發現了這個以前沒用過的 operator,筆記一下
Summary
總結來說,is 主要相信程式,as 主要是相信工程師,他們都無法準確檢查到邏輯錯誤
| 項目 | 贏家 | 原因 |
|---|---|---|
| 可維護性 | is | 邏輯集中管理 |
| 型別安全 | - | 都不驗證邏輯 |
| 重構友善 | is | 連動報錯機制 |
| 學習曲線 | as | 更直觀 |
| 工程價值 | is | 符合 SOLID 原則 |
is 的價值在於「把型別判斷邏輯變成可管理的單元」,這在大型專案中是巨大的優勢。
適用場景
適合用 as 的場景
- 單次使用、邏輯簡單
- 你 100% 確定型別(如
JSON.parse()後) - 原型開發、快速驗證
- 與外部無型別定義的 library 互動
適合用 is 的場景
- 邏輯會重複使用
- 需要在多個模組間共享
- 複雜的型別判斷(如區分 Union Type)
- 團隊協作、需要程式碼審查
- 需要為守衛邏輯寫測試
is 跟 as 的區別
決策流程圖
需要型別收窄?
│
├─ 否 → 不需要任何處理
│
└─ 是
│
├─ 邏輯只用一次?
│ └─ 是 → 用 `as`(簡潔)
│
├─ 需要抽離成函式?
│ └─ 是 → 用 `is`(型別傳播)
│
├─ 邏輯重複 3+ 次?
│ └─ 是 → 用 `is`(DRY)
│
└─ 需要測試型別判斷邏輯?
└─ 是 → 用 `is`(可測試)
基本比較
| 比較維度 | as (Type Assertion) | is (Type Predicate) |
|---|---|---|
| 基本語法 | value as Type | (param): param is Type => boolean |
| 使用位置 | 任何表達式後面 | 只能用在函式回傳型別 |
| 作用時機 | 立即、單次轉換 | 定義可復用的型別守衛 |
| 型別安全 | ❌ 編譯器完全信任你,不驗證 | ❌ 編譯器僅檢查型別兼容性,無法驗證邏輯正確性 |
| Runtime 檢查 | ❌ 無任何檢查 | ✅ 必須配合實際判斷邏輯 |
程式碼複雜度
| 維度 | as | is |
|---|---|---|
| Inline 使用 | ✅ 簡潔 list.filter(x => !!x) as string[] | ⚠️ 略冗長 list.filter((x): x is string => !!x) |
| 抽離函式 | ❌ 需額外標註 filter(fn) as Type[] | ✅ 自動推斷 filter(guardFn) |
| 多處使用 | ❌ 每處都要寫 as | ✅ 定義一次,到處使用 |
可維護性
| 場景 | as | is |
|---|---|---|
| 邏輯變更 | ❌ 需修改所有使用處 | ✅ 只改函式定義處 |
| 型別變更 | ⚠️ 必須手動更新每個 as Type | ✅ 函式簽名改了,所有呼叫處自動連動報錯 |
| 重構安全 | ❌ 容易遺漏 | ✅ 編譯器協助追蹤 |
| Code Review | ⚠️ 審查者需檢查每個 as | ✅ 只需審查守衛函式本身 |
風險比較
| 風險類型 | as | is |
|---|---|---|
| 錯誤的型別斷言 | ⚠️ 可用 as unknown as T 或是 as any 繞過,Runtime 爆炸 | ⚠️ 直接編譯通過,Runtime 爆炸 |
| 邏輯與型別不一致 | 🔴 高風險 - 分散在各處 | 🟡 中風險 - 集中在一處 |
| 重構時遺漏更新 | 🔴 高風險 - 編譯器不會提醒 | 🟢 低風險 - 型別簽名變更會連動報錯 |
| 誤用範圍 | 🔴 可在任何地方亂用 | 🟢 只能在特定場景使用(函式回傳) |
團隊協作
| 維度 | as | is |
|---|---|---|
| 新人理解成本 | 🟢 低 - 直觀 | 🟡 中 - 需理解 Type Guard 概念 |
| 程式碼審查 | 🔴 每個 as 都是潛在風險點 | 🟢 集中審查守衛函式即可 |
| 文檔價值 | ❌ 無自文檔性 | ✅ 函式名稱即文檔 (isValidUser, hasAllFields) |
| 測試便利性 | ❌ 無法獨立測試型別邏輯 | ✅ 可對守衛函式寫單元測試 |
效能比較
| 維度 | as | is |
|---|---|---|
| 編譯後程式碼 | ✅ 完全消失,零成本 | ✅ 完全消失,零成本 |
| Runtime 開銷 | ✅ 無 | ✅ 無(只是普通函式呼叫) |
| Bundle Size | ✅ 無影響 | ⚠️ 若守衛函式複雜可能增加少量 |