diff --git a/compat/fixture.ts b/compat/fixture.ts index b15f1b0..6fd9d61 100644 --- a/compat/fixture.ts +++ b/compat/fixture.ts @@ -7,7 +7,11 @@ // Why the `expectTypeOf` assertions: a compile that merely succeeds is a weak // oracle. An `any`-typed declaration would compile, but `expect-type`'s exact // equality and `.not.toBeAny()` reject `any`, so the assertions prove the -// emitted types are real. See development/ci.md § TypeScript compatibility. +// emitted types are real. Every handler *parameter* is asserted too, not just +// the matcher: the handler's member type comes from the `Member` inversion in +// the declarations, and a wrong or `any` parameter would otherwise slip +// through, since the matcher's own `(shape: T) => R` type is built from `T` and +// the handler returns. See development/ci.md § TypeScript compatibility. import { expectTypeOf } from "expect-type"; import { @@ -20,8 +24,16 @@ import { type ResultCode = "ok" | "created"; const toStatus = getPrimitiveUnionMatcher()({ - ok: () => "OK", - created: () => "CREATED", + ok: (s) => { + expectTypeOf(s).not.toBeAny(); + expectTypeOf(s).toEqualTypeOf<"ok">(); + return "OK"; + }, + created: (s) => { + expectTypeOf(s).not.toBeAny(); + expectTypeOf(s).toEqualTypeOf<"created">(); + return "CREATED"; + }, }); expectTypeOf(toStatus).not.toBeAny(); @@ -29,7 +41,13 @@ expectTypeOf(toStatus).toEqualTypeOf<(shape: ResultCode) => string>(); // The widening twin keeps each handler's own return type in the union. const toStatusW = getPrimitiveUnionMatcherW()( - { ok: () => "OK" as const }, + { + ok: (s) => { + expectTypeOf(s).not.toBeAny(); + expectTypeOf(s).toEqualTypeOf<"ok">(); + return "OK" as const; + }, + }, (rest) => { expectTypeOf(rest).not.toBeAny(); expectTypeOf(rest).toEqualTypeOf<"created">(); @@ -63,7 +81,13 @@ expectTypeOf(format).not.toBeAny(); expectTypeOf(format).toEqualTypeOf<(shape: Contact) => string>(); const formatW = getTaggedUnionMatcherW()("kind")( - { email: (e) => e.address }, + { + email: (e) => { + expectTypeOf(e).not.toBeAny(); + expectTypeOf(e).toEqualTypeOf<{ kind: "email"; address: string }>(); + return e.address; + }, + }, (rest) => { expectTypeOf(rest).not.toBeAny(); expectTypeOf(rest).toEqualTypeOf<{ kind: "phone"; number: string }>();