ts-pattern for TypeScript: complete guide with examples

Online Python Trainer for Beginners

Learn Python easily without overwhelming theory. Solve practical tasks with automatic checking, get hints in Russian, and write code directly in your browser — no installation required.

Start Course

ts-pattern for TypeScript: complete guide with examples

\n\n

The ts-pattern library brings to TypeScript a powerful and expressive pattern matching mechanism, inspired by languages such as OCaml, Rust, Haskell, and Scala. Instead of cumbersome chains of if-else or switch-case, ts-pattern allows you to describe branching logic declaratively, checking the structure and types of data. This is especially valuable when working with algebraic data types (ADTs), such as discriminated unions, optional values (Option), or results (Result).

\n\n

Why is this needed? First, the code becomes more readable and concise. Instead of parsing complex nested objects with multiple checks, you describe the desired data structure, and the library itself finds the matching variant. Second, ts-pattern provides an exhaustiveness check: if you haven't handled all possible cases, TypeScript will throw an error at compile time. This drastically reduces the number of bugs related to missed states. Third, the library is fully typed and integrates with the TypeScript type system, making refactoring safe and predictable.

\n\n

ts-pattern is not just a replacement for switch. It is a full-fledged tool for data decomposition that allows matching not only values but also their types, structures, ranges, and even custom predicates. The library is actively used in projects where reliability and expressiveness are important: from frontend applications on React/Redux to backend services on Node.js.

\n\n

Installation

\n\n

The library is installed via the npm package manager (or yarn/pnpm). Make sure your project uses TypeScript version 4.0 or higher.

\n\n
npm install ts-pattern
\n\n

After installation, the library is ready to use. No additional tsconfig.json configuration is required.

\n\n

Quick Start

\n\n

Let's start with a classic example — handling the result of an HTTP request. Imagine we have a discriminated union describing the data loading state.

\n\n
import { match } from 'ts-pattern';\n\n// Define possible states\ntype State =\n  | { status: 'idle' }\n  | { status: 'loading' }\n  | { status: 'success'; data: string }\n  | { status: 'error'; error: Error };\n\n// Function that returns text depending on the state\nfunction getStatusMessage(state: State): string {\n  return match(state)\n    .with({ status: 'idle' }, () => 'Waiting...')\n    .with({ status: 'loading' }, () => 'Loading...')\n    .with({ status: 'success' }, ({ data }) => `Data: ${data}`)\n    .with({ status: 'error' }, ({ error }) => `Error: ${error.message}`)\n    .exhaustive(); // check that all cases are handled\n}\n\n// Usage examples\nconsole.log(getStatusMessage({ status: 'idle' })); // "Waiting..."\nconsole.log(getStatusMessage({ status: 'loading' })); // "Loading..."\nconsole.log(getStatusMessage({ status: 'success', data: 'Hello, world!' })); // "Data: Hello, world!"\nconsole.log(getStatusMessage({ status: 'error', error: new Error('404') })); // "Error: 404"
\n\n

This example demonstrates the core idea: we match the state object against various patterns. Each pattern is a partial description of the object's structure. If the structure matches, the corresponding function is executed. The .exhaustive() method guarantees that we haven't forgotten to handle any of the variants.

\n\n

Main Methods and Functions

\n\n

The library provides several key functions and methods. Let's look at them in detail.

\n\n

1. match(value)

\n

Signature: match<I, O>(value: I): Match&l

Recommendations