Skip to content
TypeScript ts utility-types 3 min read

Exclude, Extract & NonNullable

Exclude, Extract, and NonNullable operate on union types rather than object types. They use distributive conditional types to filter union members in or out: Exclude removes members, Extract keeps matching members, and NonNullable strips null and undefined. They are essential for refining unions you derive from other types — for example, narrowing a set of string literals or cleaning up a T | null | undefined.

Exclude: remove matching members

Exclude<T, U> returns the members of union T that are not assignable to U. Think of it as set subtraction on unions.

type Status = "idle" | "loading" | "success" | "error";

type Settled = Exclude<Status, "idle" | "loading">;
// "success" | "error"

type WithoutNumbers = Exclude<string | number | boolean, number | boolean>;
// string

Exclude underpins Omit, which removes object keys by excluding them from keyof T. Whenever you need “this union, minus those members”, reach for Exclude.

Extract: keep matching members

Extract<T, U> is the complement: it returns the members of T that are assignable to U — the intersection of the two unions, member by member.

type Mixed = string | number | (() => void) | boolean;

type OnlyPrimitives = Extract<Mixed, string | number | boolean>;
// string | number | boolean

type OnlyCallable = Extract<Mixed, Function>;
// () => void

A common use is pulling specific variants out of a discriminated union by their discriminant:

type Event =
  | { type: "click"; x: number; y: number }
  | { type: "key"; key: string }
  | { type: "scroll"; delta: number };

type KeyEvent = Extract<Event, { type: "key" }>;
// { type: "key"; key: string }

NonNullable: strip null and undefined

NonNullable<T> removes both null and undefined from a type. It is the type-level equivalent of a non-null assertion, but safe and declarative.

type MaybeName = string | null | undefined;
type Name = NonNullable<MaybeName>; // string

function greet(name: NonNullable<MaybeName>) {
  return `Hi, ${name.toUpperCase()}`; // no null check needed
}

This is handy when a value is known to be present after a guard, or when modeling the result of a filter that drops nullish entries.

How they are built

All three are short conditional types that distribute over unions:

type MyExclude<T, U> = T extends U ? never : T;
type MyExtract<T, U> = T extends U ? T : never;
type MyNonNullable<T> = T & {}; // modern definition; previously Exclude<T, null | undefined>

For Exclude/Extract, the conditional is applied to each union member independently. Members that resolve to never vanish from the resulting union, because never is the identity element of unions. NonNullable<T> now uses the T & {} trick, since intersecting with the empty object type removes null and undefined.

Quick comparison

UtilityKeeps members that…Result for "a" | "b", U = "a"
Exclude<T, U>are NOT assignable to U"b"
Extract<T, U>ARE assignable to U"a"
NonNullable<T>are not null/undefinedn/a (single-purpose)

These utilities only filter union members. On a non-union type, Exclude<string, number> is just string — there is nothing to subtract. Distribution requires a naked type parameter over a union.

A practical combination

Combine them to derive precise types from real data shapes:

interface Form {
  name: string;
  age: number | null;
  bio: string | undefined;
}

// keys whose value can be missing
type NullableKeys = {
  [K in keyof Form]: null extends Form[K] ? K : never;
}[keyof Form]; // "age"

Here Extract/Exclude thinking drives a key-filtering mapped type, a common pattern for building typed validators.

Best Practices

  • Use Exclude/Extract to refine literal-union types instead of re-typing them by hand.
  • Reach for Extract<Union, { type: "x" }> to pull a single variant from a discriminated union.
  • Prefer NonNullable<T> over the ! non-null assertion for declarative, safe nullish removal.
  • Remember these distribute over unions only — they have no effect on non-union inputs.
  • Combine with keyof and mapped types to filter object keys by their value characteristics.
  • Keep U minimal and explicit so the subtraction/intersection intent is obvious to readers.
Last updated June 29, 2026
Was this helpful?