🔥 Remove the match and pattern example modules
They were the template's demo API, not the library's real surface. Drop them, their README walkthrough, and the tooling note that cited their disable directives, and point index.ts at the primitive matchers that remain.
This commit is contained in:
1 parent
ce3d618757
commit
a3eb6183af
5 files changed
+14
-315
No files matched your search
@@ -2,34 +2,14 @@
|
||||
|
||||
Pattern matching for TypeScript/ESM environments (F#-style, not regex).
|
||||
|
||||
## Synopsis
|
||||
|
||||
```ts
|
||||
import { match, P } from "tiny-pattern-ts";
|
||||
|
||||
const reply = (answer: "yes" | "no") =>
|
||||
match(answer)
|
||||
.with(P.literal("yes"), (): "agreed" => "agreed")
|
||||
.with(P.literal("no"), (): "declined" => "declined")
|
||||
.exhaustive();
|
||||
|
||||
reply("yes"); // "agreed"
|
||||
```
|
||||
|
||||
## Description
|
||||
|
||||
`tiny-pattern-ts` gives TypeScript the shape of F#-style pattern matching:
|
||||
a value flows through a chain of patterns, the first one that matches runs its
|
||||
handler, and the handler receives the value narrowed to that pattern's type. The
|
||||
"patterns" are ordinary objects whose `matches` method is a TypeScript type
|
||||
guard, so narrowing composes the way any other guard does.
|
||||
|
||||
It is deliberately not a regex engine and not a macro. There is no transpiler
|
||||
and no DSL to learn: `match(value)` returns a builder, `.with(pattern, handler)`
|
||||
adds a case, and the chain ends in either `.exhaustive()` or `.otherwise(...)`.
|
||||
The type-level contract is the feature — see
|
||||
[development/library.md](./development/library.md) for the design decisions and
|
||||
the known limitations.
|
||||
`tiny-pattern-ts` brings F#-style pattern matching to TypeScript. Patterns are
|
||||
ordinary objects whose `matches` method is a TypeScript type guard, so narrowing
|
||||
composes the way any other guard does. It is deliberately not a regex engine and
|
||||
not a macro: there is no transpiler and no DSL to learn, and the type-level
|
||||
contract is the feature — see [development/library.md](./development/library.md)
|
||||
for the design decisions and the known limitations.
|
||||
|
||||
## Requirements
|
||||
|
||||
@@ -39,124 +19,6 @@ the known limitations.
|
||||
both resolve on TS >= 5.0 in `node10` / `node16` / `nodenext` / `bundler`.
|
||||
- The package is **ESM-only** (no CommonJS shim).
|
||||
|
||||
## Examples
|
||||
|
||||
### Literal matching and `exhaustive()`
|
||||
|
||||
`.exhaustive()` returns the union of the handler return types and throws if no
|
||||
case matched. Annotate handler returns when you want literal types rather than
|
||||
`string`:
|
||||
|
||||
```ts
|
||||
type Answer = "yes" | "no";
|
||||
|
||||
const reply = (answer: Answer): "agreed" | "declined" =>
|
||||
match(answer)
|
||||
.with(P.literal("yes"), (): "agreed" => "agreed")
|
||||
.with(P.literal("no"), (): "declined" => "declined")
|
||||
.exhaustive();
|
||||
|
||||
reply("yes"); // "agreed"
|
||||
```
|
||||
|
||||
`exhaustive()` checks at runtime, not at compile time — TypeScript does not force
|
||||
every union member to have a case (see
|
||||
[development/library.md](./development/library.md#exhaustive-is-a-runtime-check)).
|
||||
Use `.otherwise(...)` when a fallback is wanted:
|
||||
|
||||
```ts
|
||||
const label = (answer: Answer): string =>
|
||||
match(answer)
|
||||
.with(P.literal("yes"), () => "agreed")
|
||||
.otherwise(() => "not agreed");
|
||||
```
|
||||
|
||||
### Matching by `typeof`
|
||||
|
||||
`P.type<T>(name)` pairs an explicit type `T` with the runtime `typeof` name it
|
||||
should test for:
|
||||
|
||||
```ts
|
||||
const describe = (value: unknown): string =>
|
||||
match(value)
|
||||
.with(P.type<string>("string"), (s) => `string of length ${s.length}`)
|
||||
.with(P.type<number>("number"), (n) => `number ${n.toFixed(2)}`)
|
||||
.otherwise(() => "something else");
|
||||
```
|
||||
|
||||
The supported names are `string`, `number`, `boolean`, `bigint`, `symbol`,
|
||||
`undefined`, `object`, and `function`. `"object"` matches non-null objects and
|
||||
functions; `"undefined"` compares against `undefined` directly.
|
||||
|
||||
### Structural matching and discriminated unions
|
||||
|
||||
`P.shape(shape, refine?)` checks that every key in `shape` exists on the value.
|
||||
A value that is itself a matcher is applied, otherwise it is compared with
|
||||
strict equality. To narrow to a concrete type, pass a `refine` type guard:
|
||||
|
||||
```ts
|
||||
interface Circle {
|
||||
readonly kind: "circle";
|
||||
readonly radius: number;
|
||||
}
|
||||
|
||||
interface Square {
|
||||
readonly kind: "square";
|
||||
readonly side: number;
|
||||
}
|
||||
|
||||
type Shape = Circle | Square;
|
||||
|
||||
const area = (shape: Shape): number =>
|
||||
match(shape)
|
||||
.with(
|
||||
P.shape({ kind: "circle" }, (v): v is Circle => "radius" in v),
|
||||
(c) => Math.PI * c.radius ** 2,
|
||||
)
|
||||
.with(
|
||||
P.shape({ kind: "square" }, (v): v is Square => "side" in v),
|
||||
(s) => s.side ** 2,
|
||||
)
|
||||
.exhaustive();
|
||||
```
|
||||
|
||||
Without `refine`, `P.shape` returns a matcher for the shape's own type, not the
|
||||
narrowed one. Nested matchers can be used in the shape object, for example
|
||||
`P.shape({ name: P.type<string>("string") })`.
|
||||
|
||||
### Custom guards with `when`
|
||||
|
||||
`P.when` takes a type guard and infers the narrowed type from it:
|
||||
|
||||
```ts
|
||||
const toNumber = (value: unknown): number =>
|
||||
match(value)
|
||||
.with(
|
||||
P.when((v): v is string => typeof v === "string"),
|
||||
(s) => Number.parseInt(s, 10),
|
||||
)
|
||||
.otherwise(() => 0);
|
||||
```
|
||||
|
||||
### Widening with `any`
|
||||
|
||||
`P.any<T>(predicate)` takes a plain boolean predicate and a declared type `T`,
|
||||
for cases where the predicate cannot be written as a type guard:
|
||||
|
||||
```ts
|
||||
const firstNumber = (items: readonly unknown[]): number | undefined =>
|
||||
match(items)
|
||||
.with(
|
||||
P.any<readonly number[]>(
|
||||
(v) =>
|
||||
Array.isArray(v) &&
|
||||
v.every((item) => typeof item === "number"),
|
||||
),
|
||||
(xs) => xs[0],
|
||||
)
|
||||
.otherwise(() => undefined);
|
||||
```
|
||||
|
||||
## API
|
||||
|
||||
Yet to be implemented
|
||||
|
||||
Reference in new issue
Block a user