Pick and Omit are the scalpels used to slice properties out of Object Types, then Extract and Exclude are the scalpels used to filter members out of Union Types.1. The Core Rule: Objects vs Unions#
Many developers confuse Omit and Exclude, or Pick and Extract. Memorize this rule:
- Use
Pick&Omitwhen modifying the keys of an Interface or Object Shape. - Use
Extract&Excludewhen filtering the members of a Union (A | B | C).
2. Exclude<UnionType, ExcludedMembers>#
Exclude takes a union type and removes any members that are assignable to the specified exclusion constraint.
Basic Literal Exclusion#
type AvailableColors = "red" | "green" | "blue" | "yellow";
// 🟢 Remove "red" and "green" from the union
type CoolColors = Exclude<AvailableColors, "red" | "green">;
// Inferred Type: "blue" | "yellow"
Filtering Primitives from Mixed Unions#
Exclude is incredibly useful for stripping null, undefined, or specific primitives out of broad generic unions:
type MixedUnion = string | number | boolean | null | undefined;
// 🟢 Strip out null and undefined
type ValidValues = Exclude<MixedUnion, null | undefined>;
// Inferred Type: string | number | boolean
(Note: TypeScript provides a dedicated built-in utility called NonNullable<T> that explicitly performs Exclude<T, null | undefined>!)
3. Extract<UnionType, ExtractedMembers>#
Extract is the exact inverse of Exclude. It filters a union, keeping only the members that are assignable to the specified extraction constraint.
Basic Literal Extraction#
type ValidRoles = "admin" | "editor" | "viewer" | "guest";
// 🟢 Keep ONLY "admin" or "editor"
type ElevatedRoles = Extract<ValidRoles, "admin" | "editor" | "superadmin">;
// Inferred Type: "admin" | "editor"
// (Note: "superadmin" is safely ignored because it wasn't in the original union).
4. Advanced: Extracting by Object Signature#
Because Extract and Exclude check assignability (extends), you can use them to extract complex object shapes from Discriminated Unions based on their structural signature!
Imagine an event-driven architecture (like Redux or a Web Socket payload router) with a massive union of possible events:
type AppEvent =
| { type: "CLICK"; x: number; y: number }
| { type: "HOVER"; elementId: string }
| { type: "KEYDOWN"; key: string }
| { type: "API_SUCCESS"; payload: any }
| { type: "API_ERROR"; statusCode: number };
// 🟢 Extract ONLY the event objects where the type is "CLICK" or "HOVER"
type MouseEvents = Extract<AppEvent, { type: "CLICK" | "HOVER" }>;
/* Inferred Type:
| { type: "CLICK"; x: number; y: number }
| { type: "HOVER"; elementId: string }
*/
// 🟢 Exclude API events by matching a signature pattern
type UIEvents = Exclude<AppEvent, { type: "API_SUCCESS" | "API_ERROR" }>;
/* Inferred Type:
| { type: "CLICK"; x: number; y: number }
| { type: "HOVER"; elementId: string }
| { type: "KEYDOWN"; key: string }
*/By extracting subsets of discriminated unions, you can write highly focused reducer functions that only accept the exact subset of events they are responsible for handling.
5. Under the Hood: Distributive Conditional Types#
How do Extract and Exclude actually loop through a union type? They use a TypeScript feature called Distributive Conditional Types (which we will cover fully in the Advanced Module).
Here are their internal definitions:
// If T extends U, return 'never' (discard it). Otherwise, return T (keep it).
type CustomExclude<T, U> = T extends U ? never : T;
// If T extends U, return T (keep it). Otherwise, return 'never' (discard it).
type CustomExtract<T, U> = T extends U ? T : never;When you pass a union like "A" | "B" into T, TypeScript distributes the conditional check across every individual member of the union:
- Is
"A"assignable toU? - Is
"B"assignable toU? - The results are recombined into a new union!
Summary & Next Steps#
In this episode:
- We established the Objects vs Unions Rule: (
Pick/Omitfor objects,Extract/Excludefor unions). - We filtered unwanted types from unions using
Exclude<T, U>. - We isolated specific types using
Extract<T, U>. - We extracted objects from Discriminated Unions using structural signatures.
- We revealed the Distributive Conditional Type logic powering these utilities (
T extends U ? never : T).
In Episode 37: Utility Types (ReturnType and Parameters), we will extract types directly from function signatures!

