Last Updated: 3/6/2026
API Reference
match
match(value);Create a Match object on which you can later call .with, .when, .otherwise and .run.
Signature
function match<TInput>(input: TInput): Match<TInput, TInput>;Arguments
input- Required
- the input value your patterns will be tested against.
.with
match(...)
.with(pattern, [...patterns], handler)Signature
function with<TPattern>(
pattern: Pattern<TInput, TPattern>,
handler: (selections: Selections<TPattern>, value: TInput) => TOutput
): Match<TInput, TOutput>;
// Overload for multiple patterns
function with<TPattern>(
pattern1: Pattern<TInput, TPattern>,
...patterns: Pattern<TInput, TPattern>[],
handler: (value: TInput) => TOutput
): Match<TInput, TOutput>;
// Overload for guard functions
function with<TPattern>(
pattern: Pattern<TInput, TPattern>,
when: (value: TInput) => unknown,
handler: (selection: Selection<TPattern>, value: TInput) => TOutput
): Match<TInput, TOutput>;Arguments
-
pattern: Pattern<TInput, TPattern>- Required
- The pattern your input must match for the handler to be called.
- If you provide several patterns before providing the
handler, thewithclause will match if one of the patterns matches.
-
when: (value: TInput) => unknown- Optional
- Additional condition the input must satisfy for the handler to be called.
- The input will match if your guard function returns a truthy value.
-
handler: (selections: Selections<TPattern>, value: TInput) => TOutput- Required
- Function called when the match conditions are satisfied.
- All handlers on a single
matchcase must return values of the same type,TOutput.
.when
match(...)
.when(predicate, handler)Signature
function when(
predicate: (value: TInput) => unknown,
handler: (value: TInput) => TOutput
): Match<TInput, TOutput>;Arguments
-
predicate: (value: TInput) => unknown- Required
- Condition the input must satisfy for the handler to be called.
-
handler: (value: TInput) => TOutput- Required
- Function called when the predicate condition is satisfied.
.returnType
match(...)
.returnType<TOutputOverride>()
.with(..., () => "has to be a string")
.with(..., () => "Oops".length)
// ~~~~~~~~~~~~~ ❌ `number` isn't a string!The .returnType() method allows you to control the return type of all of your branches of code.
Signature
function returnType<TOutputOverride>(): Match<TInput, TOutputOverride>;Type arguments
TOutputOverride- The type that your
matchexpression will return. All branches must return values assignable to it.
- The type that your
.exhaustive
match(...)
.with(...)
.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.
By default, .exhaustive() will throw an error if the input value wasn’t handled by any .with(...) clause.
Signature
function exhaustive(): TOutput;
function exhaustive(handler: (unexpectedValue: unknown) => TOutput): TOutput;Example
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();
const fn2 = (org: Plan, user: Permission) =>
match([org, user])
.with(['basic', 'viewer'], () => {})
.with(['basic', 'editor'], () => {})
.with(['pro', 'viewer'], () => {})
.with(['pro', 'editor'], () => {})
.exhaustive(); // Works!.otherwise
match(...)
.with(...)
.otherwise(defaultHandler)Runs the pattern-matching expression with a default handler which will be called if no previous .with() clause match the input value.
Signature
function otherwise(defaultHandler: (value: TInput) => TOutput): TOutput;Arguments
defaultHandler: (value: TInput) => TOutput- Required
- Function called if no pattern matched the input value.
- Think of it as the
default:case ofswitchstatements.
.run
match(...)
.with(...)
.run()Returns the result of the pattern-matching expression, or throws if no pattern matched the input. .run() is similar to .exhaustive(), but is unsafe because exhaustiveness is not checked at compile time.
Signature
function run(): TOutput;.narrow
match(...)
.with(...)
.narrow()
.with(...)The .narrow() method deeply narrows the input type to exclude all values that have previously been handled.
Signature
function narrow(): Match<Narrow<TInput>, TOutput>;Example
type Input = { color: 'red' | 'blue'; size: 'small' | 'large' };
declare const input: Input;
const result = match(input)
.with({ color: 'red', size: 'small' }, (red) => `Red: ${red.size}`)
.with({ color: 'blue', size: 'large' }, (red) => `Red: ${red.size}`)
.narrow() // 👈
.otherwise((narrowedInput) => {
// narrowedInput:
// | { color: 'red'; size: 'large' }
// | { color: 'blue'; size: 'small' }
});isMatching
if (isMatching(pattern, value)) {
...
}isMatching is a type guard function which checks if a pattern matches a given value. It is curried, which means it can be used in two ways.
With a single argument:
import { isMatching, P } from 'ts-pattern';
const isBlogPost = isMatching({
type: 'blogpost',
title: P.string,
description: P.string,
});
if (isBlogPost(value)) {
// value: { type: 'blogpost', title: string, description: string }
}With two arguments:
const blogPostPattern = {
type: 'blogpost',
title: P.string,
description: P.string,
} as const;
if (isMatching(blogPostPattern, value)) {
// value: { type: 'blogpost', title: string, description: string }
}Signature
export function isMatching<p extends Pattern<any>>(
pattern: p
): (value: any) => value is InvertPattern<p>;
export function isMatching<p extends Pattern<any>>(
pattern: p,
value: any
): value is InvertPattern<p>;Arguments
-
pattern: Pattern<any, any>- Required
- The pattern a value should match.
-
value?: any- Optional
- if a value is given as second argument,
isMatchingwill return a boolean. - if we only give the pattern,
isMatchingwill return another type guard function.