TypeScript Exclude<T, U> vs Extract<T, U> Explained
Learn the difference between Exclude and Extract utility types for filtering union types. Side-by-side comparison with practical examples.
Union Types
Detailed Explanation
Exclude<T, U> vs Extract<T, U>
These two utility types are complementary operations on union types. Exclude removes members; Extract keeps members.
Exclude<T, U>
Removes from T all union members that are assignable to U:
type T = "a" | "b" | "c" | "d";
type Result = Exclude<T, "a" | "c">;
// Result: "b" | "d"
Extract<T, U>
Keeps from T only union members that are assignable to U:
type T = "a" | "b" | "c" | "d";
type Result = Extract<T, "a" | "c">;
// Result: "a" | "c"
Side-by-Side Comparison
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"
With Discriminated Unions
Extract is especially powerful with discriminated unions:
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 }
How They Work Internally
Both are implemented using conditional types:
type Exclude<T, U> = T extends U ? never : T;
type Extract<T, U> = T extends U ? T : never;
Use Case
Use Exclude when you need to narrow a union by removing specific members (e.g., removing error states from a status union). Use Extract when you want to filter a union to keep only members matching a shape (e.g., extracting actions with an id property).