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プロパティを持つアクションの抽出)。

試してみる — TypeScript Utility Types

フルツールを開く