Skip to content

annotate a republished binding as typeof the binding it republishes, which ZodType widened into a lie - #238

Merged
eburgos merged 1 commit into
masterfrom
fix/republished-binding-annotation
Aug 12, 2026
Merged

annotate a republished binding as typeof the binding it republishes, which ZodType widened into a lie#238
eburgos merged 1 commit into
masterfrom
fix/republished-binding-annotation

Conversation

@eburgos

@eburgos eburgos commented Aug 12, 2026

Copy link
Copy Markdown
Owner

An item that publishes another item's binding — an alias's const, a one-slot
tuple struct over a brand, and the generic $SchemaDefault of both — annotated
it ZodType<T>. Over a branded schema that annotation does not hold:
$ZodBranded's output is the branded type while ZodType<T>'s parameter is
the unbranded one, and tsc --strict refuses the assignment. Thirteen such
errors on one emitted module, across every brand inner and in both declaration
orders.

The distinction the fix draws is structural, not nominal: an item that builds
its own expression keeps ZodType<Name>, and an item that restates a sibling's
binding says so — typeof {Name}$RawSchema, the one annotation that is true
whatever the sibling's class is. The generic default binds its factory call to
a raw const first so the same typeof applies. That is why the registry answer
was rejected on measurement: an alias written above its brand has no entry to
read, and an alias chain re-breaks at the second link — one macro invocation
sees one item, and typeof needs to know nothing about the sibling but its
name. The ReturnType<typeof Factory> spelling type-checks while silently
collapsing an inferred value to the opaque parameter, which is the trap
assignability alone does not catch.

Nothing that builds its own expression moves: an alias of a String, of a
Vec, of a map, every composite over a brand, and every brand's own binding
are pinned byte-identical, and no pre-existing expectation string changed.
Measured on the crate's real emission: thirteen TS2322s before, zero after,
declaration emit clean, and the inferred type of every parse stays exact.

just fmt, just check, just quick, just lint-all across all 68 toggles, and the
test powerset across all 68 in four partitions — all green.

…which ZodType widened into a lie

An item that publishes another item's binding — an alias's const, a one-slot
tuple struct over a brand, and the generic `$SchemaDefault` of both — annotated
it `ZodType<T>`. Over a branded schema that annotation does not hold:
`$ZodBranded`'s output is the branded type while `ZodType<T>`'s parameter is
the unbranded one, and tsc --strict refuses the assignment. Thirteen such
errors on one emitted module, across every brand inner and in both declaration
orders.

The distinction the fix draws is structural, not nominal: an item that builds
its own expression keeps `ZodType<Name>`, and an item that restates a sibling's
binding says so — `typeof {Name}$RawSchema`, the one annotation that is true
whatever the sibling's class is. The generic default binds its factory call to
a raw const first so the same `typeof` applies. That is why the registry answer
was rejected on measurement: an alias written above its brand has no entry to
read, and an alias chain re-breaks at the second link — one macro invocation
sees one item, and `typeof` needs to know nothing about the sibling but its
name. The `ReturnType<typeof Factory>` spelling type-checks while silently
collapsing an inferred value to the opaque parameter, which is the trap
assignability alone does not catch.

Nothing that builds its own expression moves: an alias of a `String`, of a
`Vec`, of a map, every composite over a brand, and every brand's own binding
are pinned byte-identical, and no pre-existing expectation string changed.
Measured on the crate's real emission: thirteen TS2322s before, zero after,
declaration emit clean, and the inferred type of every parse stays exact.

just fmt, just check, just quick, just lint-all across all 68 toggles, and the
test powerset across all 68 in four partitions — all green.
@eburgos
eburgos merged commit 5d147b0 into master Aug 12, 2026
@eburgos
eburgos deleted the fix/republished-binding-annotation branch August 12, 2026 02:23
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant