Functional pattern matching with the full power of Typescript.
Getting started
To install from npm:
npm install @effect/match
Once you have installed the library, you can import the necessary types and functions from the @effect/match
module.
import * as Match from "@effect/match"
Defining a Matcher
To define a Matcher
from a given type, you can use the type
constructor function.
You can then use the when
, not
& tag
combinators to specify the patterns to match against.
For example:
import * as Match from "@effect/match"
import { pipe } from "@effect/data/Function"
const match = pipe(
Match.type<{ a: number } | { b: string }>(),
Match.when({ a: Match.number }, (_) => _.a),
Match.when({ b: Match.string }, (_) => _.b),
Match.exhaustive,
)
console.log(match({ a: 0 }))
console.log(match({ b: "hello" }))
You can also create a Matcher
from a value using the value
constructor function.
For example:
import * as Match from "@effect/match"
import { pipe } from "@effect/data/Function"
const result = pipe(
Match.value({ name: "John", age: 30 }),
Match.when(
{ name: "John" },
(user) => `${user.name} is ${user.age} years old`,
),
Match.orElse(() => "Oh, not John"),
)
console.log(result)
Types of patterns
Predicates
Values can be tested against arbitrary functions.
import * as Match from "@effect/match"
import { pipe } from "@effect/data/Function"
const match = pipe(
Match.type<{ age: number }>(),
Match.when({ age: (age) => age >= 5 }, (user) => `Age: ${user.age}`),
Match.orElse((user) => `${user.age} is too young`),
)
console.log(match({ age: 5 }))
console.log(match({ age: 4 }))
not
patterns
not
lets you match on everything but a specific value or Schema.
import * as Match from "@effect/match"
import { pipe } from "@effect/data/Function"
const match = pipe(
Match.type<string | number>(),
Match.not("hi", (_) => "a"),
Match.orElse(() => "b"),
)
console.log(match("hello"))
console.log(match("hi"))
tag
patterns
Matches against the tag in a Discriminated Union
import * as Match from "@effect/match"
import * as E from "@effect/data/Either"
import { pipe } from "@effect/data/Function"
const match = pipe(
Match.type<E.Either<string, number>>(),
Match.tag("Right", (_) => _.right),
Match.tag("Left", (_) => _.left),
Match.exhaustive,
)
console.log(match(E.right(123)))
Evaluating a Matcher
option
A Matcher that might match a value. Returns an Option.
import * as Match from "@effect/match"
import * as E from "@effect/data/Either";
import { pipe } from "@effect/data/Function"
const result = pipe(
Match.value(E.right(0)),
Match.when({ _tag: "Right" }, (_) => _.right),
Match.option,
)
console.log(result)
exhaustive
A Matcher that marks the end of the matching process and checks if all possible matches were made. Returns the match (for Match.value
) or the evaluation function (for Match.type
).
import * as Match from "@effect/match"
import * as E from "@effect/data/Either";
import { pipe } from "@effect/data/Function"
const result = pipe(
Match.value(E.right(0)),
Match.when({ _tag: "Right" }, (_) => _.right),
Match.exhaustive,
)
orElse
A Matcher that marks the end of the matcher and allows to provide a fallback value if no patterns match. Returns the match (for Match.value
) or the evaluation function (for Match.type
).
import * as Match from "@effect/match"
import { pipe } from "@effect/data/Function"
const match = pipe(
Match.type<string | number>(),
Match.when("hi", (_) => "hello"),
Match.orElse(() => "I literally do not understand"),
)
console.log(match("hello"))
console.log(match("hi"))
either
A Matcher that might match a value. Returns an Either in the shape of Either<NoMatchResult, MatchResult>
.
import * as Match from "@effect/match"
import { pipe } from "@effect/data/Function"
const match = pipe(
Match.type<string>(),
Match.when("hi", (_) => "hello"),
Match.either,
)
console.log(match("hi"))
console.log(match("shigidigi"))
License
The MIT License (MIT)