The exhaustive Pattern Matching library for TypeScript.
ts-pattern is an exhaustive pattern matching library for TypeScript that provides a powerful alternative to traditional switch statements and nested if-else chains. With over 3.5 million weekly downloads, it has become the de facto standard for type-safe pattern matching in the TypeScript ecosystem, enabling developers to write more declarative and maintainable code.
The library leverages TypeScript's type system to provide compile-time guarantees about pattern coverage and automatic type narrowing within each branch. Unlike switch statements that only match primitive values, ts-pattern handles complex scenarios including deep object matching, array destructuring, type guards, and discriminated unions. The API is built around a chainable match() function combined with pattern helpers from the P namespace.
ts-pattern shines in codebases dealing with state machines, Redux-style reducers, API response handling, and algebraic data types. It trades a small runtime performance cost (approximately 10-12x slower than optimized if-chains) for significant gains in code readability, type safety, and developer ergonomics. The library's .exhaustive() method ensures all possible cases are handled at compile time, eliminating entire classes of runtime errors.
Developers working with complex TypeScript applications—particularly those involving union types, event-driven architectures, or functional programming patterns—find ts-pattern indispensable. It's particularly popular in React applications for reducer logic, in Node.js backends for request routing, and anywhere discriminated unions are heavily used.
import { match, P } from 'ts-pattern';
type ApiResponse<T> =
| { status: 'loading' }
| { status: 'success'; data: T }
| { status: 'error'; code: number; message: string };
type User = { id: string; name: string; role: 'admin' | 'user' };
function handleUserResponse(response: ApiResponse<User>) {
return match(response)
.with({ status: 'loading' }, () => ({
ui: 'spinner',
message: 'Fetching user...'
}))
.with(
{ status: 'success', data: { role: 'admin' } },
({ data }) => ({
ui: 'dashboard',
user: data,
permissions: ['read', 'write', 'delete']
})
)
.with(
{ status: 'success', data: { role: 'user' } },
({ data }) => ({
ui: 'dashboard',
user: data,
permissions: ['read']
})
)
.with(
{ status: 'error', code: P.when(c => c >= 500) },
({ message }) => ({
ui: 'error',
message: 'Server error: ' + message,
retryable: true
})
)
.with(
{ status: 'error' },
({ code, message }) => ({
ui: 'error',
message: `Client error (${code}): ${message}`,
retryable: false
})
)
.exhaustive();
}
const result = handleUserResponse({
status: 'success',
data: { id: '123', name: 'Alice', role: 'admin' }
});
console.log(result);
// { ui: 'dashboard', user: { ... }, permissions: ['read', 'write', 'delete'] }State Management Reducers: Replace verbose switch statements in Redux or useReducer hooks with expressive pattern matching. Match on action types while automatically narrowing payloads, capturing selected values with P.select(), and ensuring all action types are handled with .exhaustive().
API Response Handling: Process complex API responses with nested structures, matching on status codes, error types, and data shapes simultaneously. Handle Result/Option types from functional libraries by matching on discriminated unions like { success: true, data: ... } vs { success: false, error: ... }.
Form Validation: Match against validation state objects to determine UI behavior. Pattern match on combinations of field states, error types, and user interactions to declaratively define complex validation flows without nested conditionals.
Event Router/Handler Systems: Build type-safe event handling systems where different event types trigger different handlers. Match on event discriminators while automatically narrowing event payloads, ensuring every event type has a corresponding handler.
Data Transformation Pipelines: Transform heterogeneous data structures by matching on shape and type. Particularly useful when processing API data that varies by endpoint or version, allowing you to normalize data structures through pattern-based transformations.
npm install ts-patternpnpm add ts-patternbun add ts-pattern