Skip to content

write an enum-keyed map as z.partialRecord, which accepts the subsets serde writes - #237

Merged
eburgos merged 1 commit into
masterfrom
fix/partial-enum-keyed-record
Aug 12, 2026
Merged

write an enum-keyed map as z.partialRecord, which accepts the subsets serde writes#237
eburgos merged 1 commit into
masterfrom
fix/partial-enum-keyed-record

Conversation

@eburgos

@eburgos eburgos commented Aug 12, 2026

Copy link
Copy Markdown
Owner

z.record over an enumerated key schema demands every member be present, so a
partially populated HashMap<EnumKey, V> — and an empty one — was rejected by
its own generated schema. Measured against real serde payloads: a partial map
failed with one missing-key issue per absent member per field, an empty map
with all of them, while the full map alone parsed. TypeScript had said
Partial<Record<...>> all along, and the JSON document carries no required,
so Zod was the one surface rejecting what the type system and the document both
admit — and what a Rust HashMap plainly holds.

The record call is chosen off a new wire answer for an enumerated key, recorded
where a plain enum registers and forwarded by the existing brand and alias
forwarding — the constructor's question being whether the key's published Zod
binding enumerates, which a brand over an enum does even though its JSON stays
an open object. A registry miss answers as enumerated, which is what a key
naming an enum declared later reads: measured safe, since partialRecord is
runtime-identical to record over every non-enumerating key schema this crate
emits, and a forward-declared key that is not an enum is already refused
elsewhere.

TypeScript and the JSON document do not move. A stray key is still refused.
Verified on the verbatim emission with real payloads: partial, full and empty
all parse byte-identically, ajv agreeing before and after — the before-state
verdicts are recorded in the pinning test, showing Zod alone was wrong.

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.

… serde writes

`z.record` over an enumerated key schema demands every member be present, so a
partially populated `HashMap<EnumKey, V>` — and an empty one — was rejected by
its own generated schema. Measured against real serde payloads: a partial map
failed with one missing-key issue per absent member per field, an empty map
with all of them, while the full map alone parsed. TypeScript had said
`Partial<Record<...>>` all along, and the JSON document carries no `required`,
so Zod was the one surface rejecting what the type system and the document both
admit — and what a Rust `HashMap` plainly holds.

The record call is chosen off a new wire answer for an enumerated key, recorded
where a plain enum registers and forwarded by the existing brand and alias
forwarding — the constructor's question being whether the key's published Zod
binding enumerates, which a brand over an enum does even though its JSON stays
an open object. A registry miss answers as enumerated, which is what a key
naming an enum declared later reads: measured safe, since `partialRecord` is
runtime-identical to `record` over every non-enumerating key schema this crate
emits, and a forward-declared key that is not an enum is already refused
elsewhere.

TypeScript and the JSON document do not move. A stray key is still refused.
Verified on the verbatim emission with real payloads: partial, full and empty
all parse byte-identically, ajv agreeing before and after — the before-state
verdicts are recorded in the pinning test, showing Zod alone was wrong.

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 0b0cef4 into master Aug 12, 2026
@eburgos
eburgos deleted the fix/partial-enum-keyed-record branch August 12, 2026 01:28
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