Type expression

Exclude<T, U> and Extract<T, U>

  • Utility types
  • Since TypeScript 2.8

Exclude<Status, "deleted"> is the union Status without the member "deleted"; Extract<Status, "draft" | "live"> keeps only those two. They filter union types, member by member; TypeScript 2.8 added them along with conditional types.

Extract with an object shape picks members of a discriminated union: Extract<UiEvent, { type: "click" }> is the click event type, with its x and y.

At a glance

Use JSDoc in a .js file TypeScript in a .ts file
Remove members /** @typedef {Exclude<Status, "deleted">} VisibleStatus */ type VisibleStatus = Exclude<Status, "deleted">;
Keep members /** @typedef {Extract<Status, "draft" | "live">} EditableStatus */ type EditableStatus = Extract<Status, "draft" | "live">;
Pick a union member by shape /** @typedef {Extract<UiEvent, { type: "click" }>} ClickEvent */ type ClickEvent = Extract<UiEvent, { type: "click" }>;

Examples

status.js status.ts TypeScript 5.9.3 TypeScript 5.9.3, run 21 October 2026: No errors. 6.0.3 TypeScript 6.0.3, run 21 October 2026: the same as 5.9.3. No errors. 7.0.2 TypeScript 7.0.2, run 21 October 2026: the same as 5.9.3. No errors. checked 21 October 2026
/** @typedef {"draft" | "live" | "archived" | "deleted"} Status */
/** @typedef {Exclude<Status, "deleted">} VisibleStatus */
/** @typedef {Extract<Status, "draft" | "live">} EditableStatus */

/**
 * @typedef {{ type: "click", x: number, y: number }
 *   | { type: "key", key: string }
 *   | { type: "scroll", top: number }} UiEvent
 */
/** @typedef {Extract<UiEvent, { type: "click" }>} ClickEvent */

/** @param {VisibleStatus} status */
export function badge(status) {
  return status.toUpperCase();
}

/** @param {ClickEvent} event */
export function where(event) {
  return `${event.x},${event.y}`;
}

/** @type {EditableStatus} */
const editable = "draft";
badge(editable);
where({ type: "click", x: 10, y: 20 });
type Status = "draft" | "live" | "archived" | "deleted";
type VisibleStatus = Exclude<Status, "deleted">;
type EditableStatus = Extract<Status, "draft" | "live">;

type UiEvent = { type: "click"; x: number; y: number } | { type: "key"; key: string } | { type: "scroll"; top: number };
type ClickEvent = Extract<UiEvent, { type: "click" }>;

export function badge(status: VisibleStatus) {
  return status.toUpperCase();
}

export function where(event: ClickEvent) {
  return `${event.x},${event.y}`;
}

const editable: EditableStatus = "draft";
badge(editable);
where({ type: "click", x: 10, y: 20 });
Exclude and Extract filter a union.
jsconfig.json for this example
{
  "compilerOptions": {
    "checkJs": true,
    "noEmit": true,
    "strict": true,
    "target": "es2022",
    "module": "nodenext",
    "types": []
  },
  "include": ["*.js"]
}
status.js Error confirmed 5.9.3 TypeScript 5.9.3, run 21 October 2026: status.js(10,7): error TS2345: Argument of type '"deleted"' is not assignable to parameter of type '"draft" | "live" | "archived"'. 6.0.3 TypeScript 6.0.3, run 21 October 2026: the same as 5.9.3. status.js(10,7): error TS2345: Argument of type '"deleted"' is not assignable to parameter of type '"draft" | "live" | "archived"'. 7.0.2 TypeScript 7.0.2, run 21 October 2026: the same as 5.9.3. status.js(10,7): error TS2345: Argument of type '"deleted"' is not assignable to parameter of type 'VisibleStatus'. checked 21 October 2026
/** @typedef {"draft" | "live" | "archived" | "deleted"} Status */
/** @typedef {Exclude<Status, "deleted">} VisibleStatus */

/** @param {VisibleStatus} status */
export function badge(status) {
  return status.toUpperCase();
}

badge("deleted");error TS2345: Argument of type '"deleted"' is not assignable to parameter of type '"draft" | "live" | "archived"'.
A value that was excluded.
jsconfig.json for this example
{
  "compilerOptions": {
    "checkJs": true,
    "noEmit": true,
    "strict": true,
    "target": "es2022",
    "module": "nodenext",
    "types": []
  },
  "include": ["*.js"]
}

They work on unions

Both are distributive conditional types, so they act on each member of a union. They are not for object properties: to drop a property from an object type, use Omit; to keep some, Pick.

Gotchas

  • Neither checks that U matches anything. Exclude<Status, "delted"> silently removes nothing.
  • NonNullable<T> is the special case Exclude<T, null | undefined>.

Questions

What is the difference between Exclude and Omit?

Exclude removes members from a union type; Omit removes properties from an object type.

Sources

Last reviewed 20 October 2026.