介紹
TypeScript 的類型系統是圖靈完備,而釋放其全部功能的關鍵功能之一是條件類型。就像 JavaScript 中的三元運算子 (condition ? a : b) 一樣,條件類型可讓您建立類型層級邏輯:T extends U ? X : Y。這使得動態的、上下文感知的類型解析成為可能。
基本文法
條件類型檢查一個類型是否擴展另一個類型:
type IsString<T> = T extends string ? true : false;
type A = IsString<'hello'>; // true
type B = IsString<42>; // false
條件 T extends U 詢問:「T 是否可以指派給 U?」如果是,則解析到true分支;否則,為假分支。
infer 關鍵字
infer 關鍵字可讓您從條件中提取類型:
type ReturnType<T> = T extends (...args: any[]) => infer R ? R : never;
function greet() { return 'hello'; }
type G = ReturnType<typeof greet>; // string
infer R 宣告一個從符合位置推斷出的類型變數 R。這是許多實用程式類型的基礎。
分配條件類型
當條件類型與 union 一起使用時,它會分佈在每個成員上:
type ToArray<T> = T extends any ? T[] : never;
type Result = ToArray<string | number>;
// string[] | number[] (not (string | number)[])
除非您將兩側包裹起來,否則這種分佈會自動發生:
type ToArrayNonDist<T> = [T] extends [any] ? T[] : never;
type Result2 = ToArrayNonDist<string | number>;
// (string | number)[]
使用條件的內建實用程式類型
許多標準實用程式類型依賴條件類型:
// Exclude — removes types from a union
type T0 = Exclude<'a' | 'b' | 'c', 'a'>;
// 'b' | 'c'
// Extract — keeps only matching types
type T1 = Extract<string | number | (() => void), Function>;
// () => void
// NonNullable — removes null and undefined
type T2 = NonNullable<string | number | null | undefined>;
// string | number
以下是 Exclude 的實作方式:
type MyExclude<T, U> = T extends U ? never : T;
現實世界的模式
基於輸入的條件回傳類型
type AsyncResult<T> = T extends Promise<infer U> ? U : T;
async function fetchData(): Promise<string> {
return 'data';
}
type Data = AsyncResult<ReturnType<typeof fetchData>>; // string
函數重載 無重載
type StringOrNumber<T> = T extends string ? string : number;
function process<T extends string | number>(val: T): StringOrNumber<T>;
function process(val: any): any {
return typeof val === 'string' ? val.toUpperCase() : val * 10;
}
const a = process('hello'); // string
const b = process(42); // number
深層條件類型範例
type DeepReadonly<T> = {
readonly [K in keyof T]: T[K] extends object
? DeepReadonly<T[K]>
: T[K];
};
interface User {
name: string;
address: { city: string; zip: number };
}
type ReadonlyUser = DeepReadonly<User>;
// { readonly name: string; readonly address: { readonly city: string; readonly zip: number } }
結論
條件類型是類型系統的 if/else。與 infer、分佈和映射類型相結合,它們可以實現複雜的類型轉換,從而在編譯時捕獲錯誤。掌握條件來編寫真正類型安全性、自記錄的 TypeScript 程式碼。

