55bf6c24a728f29535ebed879ab69f425dce3ba0
The tagged-union matcher selected handler parameters with
`Extract<T, Record<K, V>>`, which only keeps a member whose
discriminant is a singleton literal. A property that is itself a
union (`{ color: "red" | "green" | "blue" }`) or optional
(`{ type?: "x" }`) matched no member, so every handler received
`never`, and the fallback saw the whole shape instead of the
unhandled tags.
Replace the selector with `Narrowed`, which distributes over `T`,
drops a member whose `K` cannot take the tag, and narrows `K`. The
`T[K] extends V` fast path keeps an exact member (a discriminated
union's declared interface) untouched. The fallback reuses
`Narrowed` over `Exclude<Tags, HandledTags>`, so a union-valued
property narrows to the unhandled tags rather than the whole shape.
Matching a defined tag on an optional property makes the key
required (`{ type: "x" }`); the `undefined` tag yields
`{ type?: never }` under `exactOptionalPropertyTypes` (absence) or
`{ type?: undefined }` when the property admits an explicit
`undefined`.
tiny-pattern-ts
Pattern matching for TypeScript/ESM environments (F#-style, not regex).
Description
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
for the design decisions and Caveats for the limits.
Requirements
- Node.js >= 26 (
enginesfield; pinned via.node-version). - TypeScript >= 5.0 to consume the published declarations. The emitted
.d.tsuseconsttype parameters (TS 5.0) and keep their relative.tsspecifiers; both resolve on TS >= 5.0 innode10/node16/nodenext/bundler. - The package is ESM-only (no CommonJS shim).
API
Yet to be implemented
Caveats
- Only finite universes are supported. The factory must be given a finite
union of literals;
string,numberand template literals are rejected. This is what lets the exhaustive overload be proven, so the runtimedispatchthrow stays unreachable through the typed API. - A value and its stringification must not both be present. Object keys
stringify, so a universe containing both a member and the string it
stringifies to —
1 | "1",true | "true",null | "null"— is rejected at the factory. Either form alone is fine, and one value's string form may coexist with a different value's bare form ("true" | false). symbolandbigintare not supported. Asymbolbrand is a compile-time phantom with nothing to match at runtime, and abigintis not a valid property key; neither satisfies the matcher's universe constraint.NaNand-0cannot be matched specifically. They have no literal type, so both stay part ofnumber.
License
MIT © 2025 tmu. See LICENSE.
Contributing
Contributions are documented in CONTRIBUTING.md; the reasons behind the project's decisions, rejected alternatives, and known issues live in development/. AI coding agents start at AGENTS.md.