2 min read

TypeScript Exclude and Extract

Exclude and Extract are built-in utility types that operate on Union Types. They allow you to filter unions by either removing specific members or keeping only specific members.

1. Exclude<UnionType, ExcludedMembers>

Exclude constructs a type by excluding from UnionType all union members that are assignable to ExcludedMembers.

  • Mental Model: "Remove these specific types from the list."

Basic Example

type Status = "success" | "warning" | "error" | "info";

// Remove "warning" and "info"
type CriticalStatus = Exclude<Status, "warning" | "info">;
// type CriticalStatus = "success" | "error"

Removing null and undefined

While NonNullable is usually preferred, Exclude can also do this.

type MaybeString = string | number | null | undefined;

type JustValues = Exclude<MaybeString, null | undefined>;
// type JustValues = string | number

Excluding Shapes

You can exclude types based on shape compatibility.

type Shape =
  | { kind: "circle"; radius: number }
  | { kind: "square"; side: number }
  | { kind: "triangle"; base: number };

// Remove the circle
type AngularShapes = Exclude<Shape, { kind: "circle" }>;
// type AngularShapes = { kind: "square"... } | { kind: "triangle"... }

2. Extract<Type, Union>

Extract is the opposite of Exclude. It constructs a type by extracting from Type all union members that are assignable to Union.

  • Mental Model: "Keep only these types from the list." (Intersection of two unions).

Basic Example

type Status = "success" | "warning" | "error" | "info";

// Keep only "error" and "warning"
type BadStatus = Extract<Status, "error" | "warning">;
// type BadStatus = "warning" | "error"

Finding Common Types

If you have two unions, Extract finds the overlap.

type A = "a" | "b" | "c";
type B = "b" | "c" | "d";

type Common = Extract<A, B>;
// type Common = "b" | "c"

3. How they work

Both utilities rely on Distributive Conditional Types.

// Exclude implementation
type Exclude<T, U> = T extends U ? never : T;

// Extract implementation
type Extract<T, U> = T extends U ? T : never;

When T is a union (e.g., "a" | "b"), TypeScript distributes the condition:

  1. Is "a" assignable to U?
  2. Is "b" assignable to U?

If the result is never, that member is removed from the final union.

programming/javascript/typescript/typescript programming/javascript/typescript/utility-types programming/javascript/typescript/conditional-types