🐛 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:
1 parent
2ff67801e0
commit
cce030b8e5
2 files changed
+27
-4
No files matched your search
@@ -170,3 +170,20 @@ test("getPrimitiveUnionMatcherPartialW allows gaps and widens to the union of ha
|
|||||||
assert.equal(matcher("y"), "fallback");
|
assert.equal(matcher("y"), "fallback");
|
||||||
assert.equal(matcher("z"), "fallback");
|
assert.equal(matcher("z"), "fallback");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test("getPrimitiveUnionMatcherPartialW also accepts an exhaustive pattern", () => {
|
||||||
|
// Arrange
|
||||||
|
const factory = getPrimitiveUnionMatcherPartialW<"x" | "y">();
|
||||||
|
|
||||||
|
// Act
|
||||||
|
const matcher = factory({
|
||||||
|
x: () => 1 as const,
|
||||||
|
y: () => "two" as const,
|
||||||
|
});
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
// ❌ ReturnsStrict: mixed handler returns widen to their union.
|
||||||
|
expectTypeOf(matcher).toEqualTypeOf<(shape: "x" | "y") => 1 | "two">();
|
||||||
|
assert.equal(matcher("x"), 1);
|
||||||
|
assert.equal(matcher("y"), "two");
|
||||||
|
});
|
||||||
+10
-4
@@ -55,7 +55,13 @@ export const getPrimitiveUnionMatcherPartial: <T extends string | number>() => <
|
|||||||
export const getPrimitiveUnionMatcherPartialW: <
|
export const getPrimitiveUnionMatcherPartialW: <
|
||||||
T extends string | number,
|
T extends string | number,
|
||||||
>() => <P extends PatternPrimitiveUnionPartial<unknown, T>>(
|
>() => <P extends PatternPrimitiveUnionPartial<unknown, T>>(
|
||||||
pattern: Simplify<P>,
|
/*
|
||||||
|
`Simplify<P>` is the inference hook: callers infer `P` from the argument.
|
||||||
// oxlint-disable-next-line typescript/no-explicit-any typescript/no-unsafe-type-assertion
|
the second half pins the impl parameter's `R` to `PatternReturns<P>`.
|
||||||
) => UnaryFn<T, PatternReturns<P>> = getPrimitiveUnionMatcherPartial as any;
|
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;
|
||||||
Reference in new issue
Block a user