✨ Finalize and document the public API surface

Export the matcher builder types from the barrel and rename them off the
internal Strict/Widening suffixes, so the type a factory returns is
nameable: PrimitiveUnionMatcher/W, TaggedUnionMatcher/W, and the
tagged-union factory types. Add TSDoc to every public symbol — the
declarations carry it into the published package — and pin the exported
names in src/index.test.ts.

Document the API in README and record the surface decision (and the
rejected matcher-shared export) in development/library.md.
This commit is contained in:
tmu committed 2026-09-23 21:39:15 +00:00
1 parent acf9d06ddd
commit f485b1bae2
8 files changed
+317 -20

No files matched your search

+54 -4
View File
@@ -44,7 +44,14 @@ type MustBePartial<T extends Matchable, Handled> =
// Strict returns: one common `R`. Overload order is load-bearing:
// #1 Handlers (first) -> the exhaustive form and the autocomplete popup
// #2 Fallback (last) -> accepts a partial handler map plus a fallback
interface PrimitiveUnionMatcherStrict<T extends Matchable> {
/**
* The builder returned by {@link getPrimitiveUnionMatcher}: call it with a
* handler map for every member of `T` to get a strict matcher, or with a partial
* map plus a fallback.
*
* @typeParam T - The finite universe of primitive members to match.
*/
export interface PrimitiveUnionMatcher<T extends Matchable> {
<R>(handlers: Handlers<T, R> & UniverseGate<T>): UnaryFn<T, R>;
<
R,
@@ -59,7 +66,14 @@ interface PrimitiveUnionMatcherStrict<T extends Matchable> {
// Widened returns: the union of every handler's return type. `P` is inferred
// from the whole handler map, whose closed constraint supplies the
// contextual/autocomplete type.
interface PrimitiveUnionMatcherWidening<T extends Matchable> {
/**
* The builder returned by {@link getPrimitiveUnionMatcherW}: like
* {@link PrimitiveUnionMatcher}, but the result's return type is the union of
* every handler's return type instead of one common `R`.
*
* @typeParam T - The finite universe of primitive members to match.
*/
export interface PrimitiveUnionMatcherW<T extends Matchable> {
<P extends Exact<Handlers<T, unknown>, P>>(
handlers: P & UniverseGate<T>,
): UnaryFn<T, PatternReturns<P>>;
@@ -96,9 +110,45 @@ const dispatch =
shape as never,
);
/**
* Create a matcher for a finite primitive universe, with one common return type.
*
* The universe `T` must be a finite union of literals with no
* value/stringification collision: broad members (`string`, `number`, template
* literals) and `true | "true"` / `1 | "1"` are rejected at the call site. The
* returned builder takes a handler map keyed by the members; supplying a second
* fallback argument allows a partial map and receives the unhandled remainder.
*
* @typeParam T - The finite universe of primitive members to match.
* @returns A builder for the handler map, or the handler map plus a fallback.
* @example
* const describe = getPrimitiveUnionMatcher<"yes" | "no">()({
* yes: () => "agreed",
* no: () => "declined",
* });
* describe("yes"); // "agreed"
*/
export const getPrimitiveUnionMatcher = <
T extends Matchable,
>(): PrimitiveUnionMatcherStrict<T> => dispatch;
>(): PrimitiveUnionMatcher<T> => dispatch;
/**
* Create a matcher for a finite primitive universe whose return type is the
* union of every handler's return type.
*
* The widening counterpart of {@link getPrimitiveUnionMatcher}: use it when the
* handlers return different types and the union, not one common `R`, is wanted.
* The universe constraint and the optional fallback are identical.
*
* @typeParam T - The finite universe of primitive members to match.
* @returns A builder for the handler map, or the handler map plus a fallback.
* @example
* const reply = getPrimitiveUnionMatcherW<"yes" | "no">()({
* yes: () => 1,
* no: () => "declined",
* });
* // reply: (shape: "yes" | "no") => number | string
*/
export const getPrimitiveUnionMatcherW = <
T extends Matchable,
>(): PrimitiveUnionMatcherWidening<T> => dispatch;
>(): PrimitiveUnionMatcherW<T> => dispatch;