TypeScript Exclude<T, U>とExtract<T, U>の解説
ユニオン型のフィルタリングに使うExcludeとExtractユーティリティ型の違いを学びます。実践的な例を交えた並列比較を紹介します。
Union Types
詳細な説明
Exclude<T, U> vs Extract<T, U>
この2つのユーティリティ型はユニオン型に対する補完的な操作です。Excludeはメンバーを除外し、Extractはメンバーを保持します。
Exclude<T, U>
TからUに代入可能なすべてのユニオンメンバーを除外します:
type T = "a" | "b" | "c" | "d";
type Result = Exclude<T, "a" | "c">;
// 結果: "b" | "d"
Extract<T, U>
TからUに代入可能なユニオンメンバーのみを保持します:
type T = "a" | "b" | "c" | "d";
type Result = Extract<T, "a" | "c">;
// 結果: "a" | "c"
並列比較
type AllEvents = "click" | "scroll" | "keypress" | "resize" | "load";
type MouseEvents = "click" | "scroll";
type NonMouseEvents = Exclude<AllEvents, MouseEvents>;
// "keypress" | "resize" | "load"
type OnlyMouseEvents = Extract<AllEvents, MouseEvents>;
// "click" | "scroll"
判別共用体との使用
Extractは判別共用体で特に強力です:
type Action =
| { type: "ADD_TODO"; text: string }
| { type: "TOGGLE_TODO"; id: number }
| { type: "DELETE_TODO"; id: number };
type TodoIdActions = Extract<Action, { id: number }>;
// { type: "TOGGLE_TODO"; id: number } | { type: "DELETE_TODO"; id: number }
内部実装
どちらも条件型を使って実装されています:
type Exclude<T, U> = T extends U ? never : T;
type Extract<T, U> = T extends U ? T : never;
ユースケース
ユニオンから特定のメンバーを除外して絞り込む場合はExcludeを使用します(例:ステータスユニオンからエラー状態を除外)。特定の形状に一致するメンバーのみを保持するフィルタリングにはExtractを使用します(例:idプロパティを持つアクションの抽出)。