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();