dismatchdismatch
Standalone API

Matching

match — exhaustive pattern matching that returns a value, and matchWithDefault — partial matching with a Default fallback.

match

Exhaustive pattern matching. TypeScript errors if a variant is missing.

import { match } from "dismatch";

type Shape =
  | { type: "circle"; radius: number }
  | { type: "rectangle"; width: number; height: number };

const area = match(shape)({
  circle: ({ radius }) => Math.PI * radius ** 2,
  rectangle: ({ width, height }) => width * height,
});

Each handler receives the data fields of its variant — never the discriminant. Missing a variant is a compile-time error; passing one that isn't on the union is also an error.

match returns a single value. To produce a function you can reuse — call many times, drop into array.map, or compose in a pipe — bind handlers through createPipeHandlers or a createUnion factory.

Try in Playground

Custom discriminant

match(event, "kind")({
  click: ({ x }) => `clicked at ${x}`,
  key: ({ code }) => `pressed ${code}`,
});

Runtime safety

If a value reaches match with a variant not in the handler map (for example because data was deserialised from an external source), match throws UnknownVariantError. Use matchWithDefault when you want to route unknown variants to a fallback instead.

matchWithDefault

Partial matching with a Default fallback. The fallback receives the full union item (with the discriminant), so you can branch on it inside.

import { matchWithDefault } from "dismatch";

const banner = matchWithDefault(result)({
  error: ({ message }) => `Error: ${message}`,
  Default: () => "All good",
});

matchWithDefault never throws UnknownVariantError — anything not handled explicitly routes to Default.

Try in Playground

When Default needs the variant

If Default should distinguish between unhandled variants, branch on the discriminant inside it:

const label = matchWithDefault(notification)({
  push: ({ message }) => `[PUSH] ${message}`,
  Default: (item) => {
    if (item.type === "email") return `[EMAIL] ${item.subject}`;
    if (item.type === "sms") return `[SMS] ${item.from}`;
    return "[unknown]";
  },
});

Reach for what next

  • Need to handle every variant but return a transformed union, not a scalar? Use mapAll.
  • Need to aggregate across a collection? Use fold.
  • Need to handle async handlers? Use matchAsync or matchWithDefaultAsync.

On this page