Skip to content

match โ€‹

Minified1.00 KBMinzipped305 B

Zero-runtime exhaustive pattern matching, inspired by ts-pattern and pattycake.

This library is a lightweight alternative to ts-pattern, with an optional Babel plugin that compiles match expressions to fast, plain JavaScript.

Features โ€‹

  • Very small size
  • Up to 60x faster than ts-pattern
  • 600+ tests
  • Type-safe exhaustiveness checks
  • Match against literals, primitives, and shallow objects
  • Eager (case(pattern, result)) and lazy (case(pattern, () => result)) matching
  • Fallback methods: or, orElse, orThrow

Examples โ€‹

ts
import { match } from "@monstermann/match"

// Match primitives:
match(value)
    .case(1, 2)
    .case(2, 3)
    .orElse(v => v + 1)

// Match object shapes:
match({ value: foo })
    .shape({ value: 1 }, 2)
    .shape({ value: 2 }, 3)
    .or(0)

// Match with conditions:
match({ value: foo })
    .cond(v => v.value > 0, "positive")
    .cond(v => v.value < 0, "negative")
    .or("zero")

Babel plugin โ€‹

The Babel plugin can optimize your code to be as fast as hand-written if/else statements.

ts
import { match } from "@monstermann/match"

match(value)
    .case(1, 2)
    .case(2, 3)
    .orElse(v => v + 1)
ts
  value === 1 ? 2 
: value === 2 ? 3 
: value + 1
ts
import { match } from "@monstermann/match"

match({ value: foo })
    .shape({ value: 1 }, 2)
    .shape({ value: 2 }, 3)
    .or(0)
ts
  foo === 1 ? 2
: foo === 2 ? 3
: 0
ts
import { match } from "@monstermann/match"

match({ value: foo })
    .cond(v => v.value > 0, "positive")
    .cond(v => v.value < 0, "negative")
    .or("zero")
ts
  foo > 0 ? "positive" 
: foo < 0 ? "negative" 
: "zero"
ts
import { match } from "@monstermann/match"

match(expensive())
    .shape({ value: undefined }, "undefined")
    .cond((v) => isString(v.value), "string")
    .cond((v) => isNumber(v.value), "number")
    .or("unknown")
ts
((_v) =>
    _v && typeof _v === "object" && _v.value === undefined ? "undefined"
    : isString(_v.value) ? "string"
    : isNumber(_v.value) ? "number"
    : "unknown"
)(expensive())

Benchmarks โ€‹

  • Runtime: Node v24.0.1
  • System: Apple M1 Max
casesummaryops/sectime/opmarginsamples
@monstermann/babel-plugin-match๐Ÿฅ‡36M21nsยฑ0.09%47M
@monstermann/match-29%25M33nsยฑ0.05%30M
ts-pattern-88%4M279nsยฑ5.25%4M
shape (object expression)summaryops/sectime/opmarginsamples
@monstermann/babel-plugin-match๐Ÿฅ‡37M21nsยฑ0.05%49M
@monstermann/match-72%10M103nsยฑ0.56%10M
ts-pattern-98%597K2ยตsยฑ5.92%557K
shape (identifier)summaryops/sectime/opmarginsamples
@monstermann/babel-plugin-match๐Ÿฅ‡37M20nsยฑ0.08%49M
@monstermann/match-69%12M92nsยฑ1.13%11M
ts-pattern-98%591K2ยตsยฑ1.18%562K
condsummaryops/sectime/opmarginsamples
@monstermann/babel-plugin-match๐Ÿฅ‡34M22nsยฑ0.04%45M
@monstermann/match-27%24M36nsยฑ0.05%28M
ts-pattern-73%9M134nsยฑ6.87%7M

Installation โ€‹

sh
npm install @monstermann/match
npm install -D @monstermann/babel-plugin-match
sh
pnpm add @monstermann/match
pnpm add -D @monstermann/babel-plugin-match
sh
yarn add @monstermann/match
yarn add -D @monstermann/babel-plugin-match
sh
bun add @monstermann/match
bun add -D @monstermann/babel-plugin-match

Please consult your bundler of choice on how to enable Babel plugins, some examples:

vite + @vitejs/plugin-react
ts
import { defineConfig } from "vite";
import react from "@vitejs/plugin-react";

export default defineConfig(() => ({
    plugins: [
        react({
            babel: {
                plugins: [["@monstermann/babel-plugin-match"]],
            },
        }),
    ],
}));
vite + vite-plugin-babel
ts
import { defineConfig } from "vite";
import babel from "vite-plugin-babel";

export default defineConfig({
    plugins: [babel()],
});
json
{
    "plugins": [["@monstermann/babel-plugin-match"]]
}