🐛 Type partial W matcher without an any cast

getPrimitiveUnionMatcherPartialW was declared with the intended
P-inferring signature but assigned via `as any`, hiding that the
declared parameter was not assignable to the implementation's. The
union in PatternPrimitiveUnionPartial makes the `_` arm demand
`_ ∈ keyof P`, which the exhaustive arm cannot prove.

Intersect the inference hook Simplify<P> with the implementation's
parameter shape, R pinned to PatternReturns<P>, so the assignment
type-checks while callers keep inferring P from the argument.

Add a spec for the exhaustive (no `_`) pattern.
This commit is contained in:
tmu committed 2026-09-16 19:10:40 +00:00
1 parent 2ff67801e0
commit cce030b8e5
2 files changed
+27 -4

No files matched your search

+10 -4
View File
@@ -55,7 +55,13 @@ export const getPrimitiveUnionMatcherPartial: <T extends string | number>() => <
export const getPrimitiveUnionMatcherPartialW: <
T extends string | number,
>() => <P extends PatternPrimitiveUnionPartial<unknown, T>>(
pattern: Simplify<P>,
// oxlint-disable-next-line typescript/no-explicit-any typescript/no-unsafe-type-assertion
) => UnaryFn<T, PatternReturns<P>> = getPrimitiveUnionMatcherPartial as any;
/*
`Simplify<P>` is the inference hook: callers infer `P` from the argument.
the second half pins the impl parameter's `R` to `PatternReturns<P>`.
that makes the `= getPrimitiveUnionMatcherPartial` assignment type-check.
neither half works alone.
without the witness the union's `_` arm demands `_ ∈ keyof P`.
without `Simplify<P>` the parameter types do not compare.
*/
pattern: Simplify<P> & PatternPrimitiveUnionPartial<PatternReturns<P>, T>,
) => UnaryFn<T, PatternReturns<P>> = getPrimitiveUnionMatcherPartial;