介紹
TypeScript 4.9 中引入的 satisfies 運算子是一項強大的功能,旨在提高類型安全性,同時保持開發人員的靈活性。
但是,區分 satisfies、類型註解 (: Type) 和類型斷言 (as Type) 之間的差異可能會令人困惑。本指南詳細介紹了 satisfies 運算子的機制,並分享了生產程式碼庫的實際用例。
1. 標準類型註解的限制(:)
讓我們回顧一下標準類型註釋的限制。
想像設計一個調色板主題配置。有些顏色被命名為字串文字,而其他顏色則為數字 RGB 陣列:
type Color = string | [number, number, number];
// Palette definition
type Palette = {
primary: Color;
secondary: Color;
danger: Color;
};
// Declaring our palette using standard type annotations
const themePalette: Palette = {
primary: "blue",
secondary: [0, 128, 0], // Green (RGB)
danger: "red"
};
一切編譯都很好。但是,如果我們存取 themePalette.primary 並嘗試運行像 toUpperCase() 這樣的字串方法,編譯器會抱怨:
// Error: Property 'toUpperCase' does not exist on type 'Color'.
// Property 'toUpperCase' does not exist on type '[number, number, number]'.
themePalette.primary.toUpperCase();
為什麼會出現這個錯誤?
透過使用 : Palette 註釋,我們指示 TypeScript 擴充 themePalette 的屬性以符合 Palette 類型定義。編譯器會丟棄 primary 被指派了字串 "blue" 的特定知識。相反,它假設 primary 在任何時候都可以是字串或數組,迫使您編寫繁瑣的類型保護。
2. 解決問題滿足
satisfies 運算子解決了這種情況。
它指示 TypeScript 驗證物件是否與特定類型結構匹配,但保留指定值的精確、最窄的推斷類型。
重構滿足
const themePalette = {
primary: "blue",
secondary: [0, 128, 0],
danger: "red"
} satisfies Palette; // Verify compatibility with Palette but keep the literal types
使用 satisfies 可以帶來兩個直接的好處:
好處 1:精確類型推斷保留
// Compiles perfectly!
// TypeScript knows themePalette.primary is definitely a string
themePalette.primary.toUpperCase();
// Also compiles perfectly!
// The compiler knows secondary is a 3-element tuple of numbers
themePalette.secondary.map(v => v * 2);
好處 2:及早發現拼字錯誤
由於編譯器會根據目標類型驗證物件結構,因此任何遺失的屬性或不正確的類型分配都會立即觸發編譯警告。
const badPalette = {
primary: "blue",
secondary: [0, 128, 0],
danger: 12345, // Error: number is not assignable to type Color
warning: "orange" // Error: warning does not exist on type Palette
} satisfies Palette;
3. 實際用例:保護記錄上的物件金鑰
另一個強大的用例是使用 Record 類型管理鍵值映射。
例如,定義使用者存取權限時:
type UserRole = "admin" | "editor" | "viewer";
// Map each role to a boolean access value
const rolePermissions = {
admin: true,
editor: true,
viewer: false
} satisfies Record<UserRole, boolean>;
此處使用 satisfies 可確保:
UserRole中宣告的每個角色都必須在物件中定義。如果忘記包含viewer,編譯器會拋出錯誤。rolePermissions的鍵仍輸入為確切的角色字串 ("admin" | "editor" | "viewer"),而不是一般字串,從而啟用 IDE 自動完成功能。
結論:類型定義指南
編寫 TypeScript 時,請使用下列經驗規則來選擇正確的鍵入語法:
- 類型註解 (
: Type): 將此用於函數參數、傳回簽名,或當您明確想要擴大類型聲明以限制對子屬性的存取時。 - 類型斷言 (
as Type): 僅當解析外部 API 輸入時使用此選項,其中 TypeScript 無法解析類型,但您絕對確定結構(謹慎使用)。 satisfies運算子 (satisfies Type): 在聲明本機配置、常數或狀態記錄時使用它來驗證它們是否遵守定義的結構,而不丟棄所指派值的確切類型。
使用 satisfies 運算子可以幫助您編寫更乾淨、類型安全的程式碼,同時減少樣板轉換。

