{"id":12185,"library":"ts-pattern","title":"TS-Pattern","description":"TS-Pattern is an exhaustive pattern matching library for TypeScript, providing a typesafe and highly ergonomic API to handle complex conditional logic. It is currently at version 5.9.0 and receives regular updates, often including new pattern types, performance improvements, and type inference enhancements. Key differentiators include its extensive support for various data structures (objects, arrays, tuples, sets, maps, primitives), robust type inference, and crucial exhaustiveness checking, ensuring all possible cases are handled at compile-time. It aims to provide a user-land implementation of pattern matching, similar to those found in functional languages, anticipating a future TC39 proposal, while maintaining a tiny bundle footprint of around 2kB.","status":"active","version":"5.9.0","language":"javascript","source_language":"en","source_url":"ssh://git@github.com/gvergnaud/ts-pattern","tags":["javascript","pattern","matching","pattern-matching","typescript","match-with","match","switch","adt"],"install":[{"cmd":"npm install ts-pattern","lang":"bash","label":"npm"},{"cmd":"yarn add ts-pattern","lang":"bash","label":"yarn"},{"cmd":"pnpm add ts-pattern","lang":"bash","label":"pnpm"}],"dependencies":[],"imports":[{"note":"TS-Pattern is primarily consumed as an ESM module. CommonJS `require` syntax is not idiomatic and might lead to type inference issues in newer TypeScript projects.","wrong":"const match = require('ts-pattern').match;","symbol":"match","correct":"import { match } from 'ts-pattern';"},{"note":"The 'P' object is a namespace containing various pattern utilities (wildcards, predicates, etc.). It should be imported directly as a named import, not as a default or star import.","wrong":"import * as P from 'ts-pattern';","symbol":"P","correct":"import { P } from 'ts-pattern';"},{"note":"Used for validating the shape of data against a pattern. Available as a named export.","symbol":"isMatching","correct":"import { isMatching } from 'ts-pattern';"}],"quickstart":{"code":"import { match, P } from 'ts-pattern';\n\ntype UserRole = 'admin' | 'editor' | 'viewer';\n\ntype UserProfile = \n  | { role: 'admin'; permissions: string[]; department: string }\n  | { role: 'editor'; projects: string[]; lastLogin: Date }\n  | { role: 'viewer'; lastViewed: string; theme: 'dark' | 'light' };\n\nconst getUserDashboardContent = (user: UserProfile): string => {\n  return match(user)\n    .with({ role: 'admin', department: P.select('dept') }, ({ dept }) => \n      `Welcome Admin! You manage the ${dept} department.`\n    )\n    .with({ role: 'editor', projects: P.array(P.string) }, (editor) => \n      `Hello Editor! Your active projects are: ${editor.projects.join(', ')}.`\n    )\n    .with({ role: 'viewer', theme: 'dark' }, () => \n      `Viewer mode: Enjoy your dark theme.`\n    )\n    .with({ role: 'viewer', theme: 'light' }, () => \n      `Viewer mode: Enjoy your light theme.`\n    )\n    .exhaustive();\n};\n\nconst adminUser: UserProfile = { role: 'admin', permissions: ['full'], department: 'IT' };\nconst editorUser: UserProfile = { role: 'editor', projects: ['Project Alpha', 'Project Beta'], lastLogin: new Date() };\nconst viewerUserDark: UserProfile = { role: 'viewer', lastViewed: 'docs', theme: 'dark' };\n\nconsole.log(getUserDashboardContent(adminUser));\nconsole.log(getUserDashboardContent(editorUser));\nconsole.log(getUserDashboardContent(viewerUserDark));","lang":"typescript","description":"This example demonstrates pattern matching on a discriminated union `UserProfile` using `match` and `P.select` for extracting values, `P.array` for matching array types, and `exhaustive` to ensure all cases are handled, returning a personalized dashboard message."},"warnings":[{"fix":"Review object patterns involving Symbol keys to ensure they explicitly match the desired Symbol values. If you previously relied on symbols being ignored, you might need to adjust your patterns or input data.","message":"Symbol keys are now considered in object patterns. Previously, symbol keys in objects were ignored during pattern matching, meaning `isMatching({ [symbolA]: 'bar' }, obj)` would incorrectly return true if `obj` was `{ [symbolA]: 'foo' }` (matching the empty object part).","severity":"breaking","affected_versions":">=5.3.1"},{"fix":"Ensure that the pattern provided to `isMatching` is compatible with the type of the value it's being compared against. Correct any type mismatches in the pattern definition.","message":"When using `isMatching` with two parameters (pattern and value), the pattern now undergoes type-checking against the value's type. This prevents passing patterns that could never match the provided value.","severity":"breaking","affected_versions":">=5.6.0"},{"fix":"You can pass a custom handler function to `.exhaustive()` to define what should happen when an unexpected value is received. For example, `match(...).with(...).exhaustive((unexpected: unknown) => { throw new MyCustomError(unexpected); });`","message":"The `.exhaustive()` method, by default, throws an error if no `with` clause matches the input value. While this indicates a type inconsistency, in rare scenarios, you might want to customize this behavior.","severity":"gotcha","affected_versions":">=5.7.0"},{"fix":"Utilize the `.narrow()` method after a `with` clause to explicitly narrow the input type for subsequent patterns, excluding values already handled. This gives more fine-grained control over deep type narrowing.","message":"When working with deeply nested union types or nullable properties, TypeScript's inference might not always narrow types as aggressively as desired within complex pattern matching scenarios.","severity":"gotcha","affected_versions":">=5.8.0"}],"env_vars":null,"last_verified":"2026-04-19T00:00:00.000Z","next_check":"2026-07-18T00:00:00.000Z","problems":[{"fix":"Add a `.with()` clause for any missing cases or use an `.otherwise(() => ...)` clause as a fallback. For deeply nested types, ensure type guards are precise or use `.narrow()` to guide inference.","cause":"This error typically occurs when the `.exhaustive()` method cannot confirm that all possible cases of the input type have been handled by the preceding `.with()` or `.otherwise()` clauses, meaning some branches are implicitly 'never' reached by the patterns.","error":"Argument of type '{ type: \"one\"; } | { type: \"two\"; }' is not assignable to parameter of type 'never'."},{"fix":"Review your input type `T` for `match` and ensure your patterns accurately reflect the possible shapes within `T`. This might involve refining discriminated unions or correcting object structures.","cause":"This usually indicates a type mismatch between the expected input type of the `match` function and the pattern being provided in a `.with()` clause. The pattern you're trying to match is incompatible with the type `T` of the `match` input.","error":"Type '{ type: \"someType\"; }' is not assignable to type 'P.Pattern<T>'"},{"fix":"Inspect the `P.select()` pattern to confirm it extracts the expected type. Also, verify the type signature of your callback function in `.with()` to ensure it correctly handles the types inferred by `ts-pattern`.","cause":"This is a general TypeScript error that can arise if a `P.select()` pattern extracts a value with an unexpected type, or a callback function within `.with()` receives arguments of types that don't match its signature.","error":"TS2345: Argument of type 'string' is not assignable to parameter of type 'number'."}],"ecosystem":"npm"}