Skip to content

match

Minified1.04 KBMinzipped309 B

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

This library is a lightweight alternative to ts-pattern, with an optional unplugin that compiles match expressions to plain & fast JavaScript, where applicable.

Features

  • Very small size
  • Up to 60x faster than ts-pattern
  • 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
    .shape({ value: foo })
    .case({ value: 1 }, 2)
    .case({ value: 2 }, 3)
    .or(0)

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

Unplugin

The unplugin can optimize your code to be as fast as hand-written if/else statements, with the help of the Oxidation Compiler, for example:

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

match(value)
    .case(1, 2)
    .case(2, 3)
    .or(4)
ts
  value === 1 ? 2 
: value === 2 ? 3 
: 4

Benchmarks

Bun

  • Runtime: Bun v1.2.19
  • CPU: AMD Ryzen 9 7900 12-Core
casesummaryops/sectime/opmarginsamples
@monstermann/unplugin-match🥇41M26ns±0.07%39M
@monstermann/match-15%35M32ns±0.45%32M
ts-pattern-95%2M762ns±0.33%1M
shape (object expression)summaryops/sectime/opmarginsamples
@monstermann/unplugin-match🥇41M27ns±0.21%38M
@monstermann/match-64%15M85ns±0.65%12M
ts-pattern-97%1M980ns±0.28%1M
shape (identifier)summaryops/sectime/opmarginsamples
@monstermann/unplugin-match🥇41M25ns±0.06%39M
@monstermann/match-63%15M79ns±0.58%13M
ts-pattern-97%1M975ns±0.31%1M
condsummaryops/sectime/opmarginsamples
@monstermann/unplugin-match🥇41M26ns±0.13%38M
@monstermann/match-51%20M59ns±0.65%17M
ts-pattern-76%10M138ns±0.29%7M

Node

  • Runtime: Node v25.1.0
  • CPU: AMD Ryzen 9 7900 12-Core
casesummaryops/sectime/opmarginsamples
@monstermann/unplugin-match🥇42M25ns±0.09%40M
@monstermann/match-7.7%39M28ns±0.63%35M
ts-pattern-87%5M219ns±3.38%5M
shape (object expression)summaryops/sectime/opmarginsamples
@monstermann/unplugin-match🥇42M25ns±0.04%40M
@monstermann/match-65%15M70ns±0.15%14M
ts-pattern-98%657K2µs±7.02%608K
shape (identifier)summaryops/sectime/opmarginsamples
@monstermann/unplugin-match🥇42M25ns±0.11%40M
@monstermann/match-66%14M72ns±0.08%14M
ts-pattern-98%658K2µs±5.66%618K
condsummaryops/sectime/opmarginsamples
@monstermann/unplugin-match🥇42M25ns±0.07%40M
@monstermann/match-12%37M29ns±0.55%34M
ts-pattern-68%14M84ns±0.60%12M

Installation

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

Setup

ts
// vite.config.ts
import match from "@monstermann/unplugin-match/vite";

export default defineConfig({
    plugins: [match()],
});
ts
// rollup.config.js
import match from "@monstermann/unplugin-match/rollup";

export default {
    plugins: [match()],
};
ts
// rolldown.config.js
import match from "@monstermann/unplugin-match/rolldown";

export default {
    plugins: [match()],
};
ts
// webpack.config.js
module.exports = {
    plugins: [require("@monstermann/unplugin-match/webpack")()],
};
ts
// rspack.config.js
module.exports = {
    plugins: [require("@monstermann/unplugin-match/rspack")()],
};
ts
// esbuild.config.js
import { build } from "esbuild";
import match from "@monstermann/unplugin-match/esbuild";

build({
    plugins: [match()],
});

Usage

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

// Match a literal or primitive:
match(value);

// Or match an object:
match.shape(value);

// Optionally set a strict return type:
.returnType<Type>()

// Match against a pattern:
.case(value, result)
.onCase(value, (match) => result)

// Or match against a predicate:
.cond((unmatched) => boolean, result)
.onCond((unmatched) => boolean, (match) => result)

// Handle result:
.or(fallback)
.orElse((unmatched) => fallback)
.orThrow()