Skip to Content
Exhaustive

Last Updated: 3/6/2026


.exhaustive()

Runs the pattern-matching expression and returns its result. It also enables exhaustiveness checking, making sure that we have handled all possible cases at compile time.

Signature

function exhaustive(): TOutput; function exhaustive(handler: (unexpectedValue: unknown) => TOutput): TOutput;

Default Behavior

By default, .exhaustive() will throw an error if the input value wasn’t handled by any .with(...) clause. This should only happen if your types are incorrect.

type Permission = 'editor' | 'viewer'; type Plan = 'basic' | 'pro'; const fn = (org: Plan, user: Permission) => match([org, user]) .with(['basic', 'viewer'], () => {}) .with(['basic', 'editor'], () => {}) .with(['pro', 'viewer'], () => {}) // Fails with `NonExhaustiveError<['pro', 'editor']>` // because the `['pro', 'editor']` case isn't handled. .exhaustive();

Custom Error Handler

You can pass your own handler function as a parameter to decide what should happen if an unexpected value has been received.

Throw Custom Error

match(...) .with(...) .exhaustive((unexpected: unknown) => { throw MyCustomError(unexpected); })

Log and Return Default

match<string, number>(...) .with(P.string, (str) => str.length) .exhaustive((notAString: unknown) => { console.log(`received an unexpected value: ${notAString}`); return 0; })

Type Safety

The exhaustiveness checking works at compile time. TypeScript will show an error if you haven’t handled all possible cases:

type Status = 'idle' | 'loading' | 'success' | 'error'; const getStatusMessage = (status: Status) => match(status) .with('idle', () => 'Ready') .with('loading', () => 'Loading...') .with('success', () => 'Done!') // TypeScript error: missing 'error' case .exhaustive();