Capítulo 21 de 61
z.record(keySchema, valueSchema) validates dictionary-shaped objects (Record<K, V>), with three variants controlling how strictly keys are checked: exhaustive (default with enum keys), partial, and loose (pass-through).
z.record(keySchema, valueSchema): the key schema must be assignable to string | number | symbol; numeric key schemas validate that keys are valid numeric strings (and can carry further numeric constraints like .min()/.step()).z.enum() or z.literal(), z.record() requires every possible key to be present, mirroring TypeScript's Record<"a"|"b", string> behavior.z.partialRecord(keySchema, valueSchema): skips that exhaustiveness check, so an enum/literal-keyed record can have a subset of its keys.z.looseRecord(keySchema, valueSchema): unlike the default (which errors on keys not matching the key schema), passes through non-matching keys unchanged — useful combined with .and() to model "one specific field plus a pattern of extra fields."const IdCache = z.record(z.string(), z.string()); // Record<string, string>
// numeric keys validate as numeric strings, with numeric constraints
const intKeys = z.record(z.int().step(1).min(0).max(10), z.string());
intKeys.parse({ 0: "zero", 12: "twelve" }); // "12" fails — out of range
// enum keys require every key present (exhaustive)
const Keys = z.enum(["id", "name", "email"]);
const Person = z.record(Keys, z.string()); // all 3 keys required
// partial: skip the exhaustiveness check
const PartialPerson = z.partialRecord(Keys.or(z.never()), z.string());
// loose: pass through keys that don't match the key schema
const schema = z
.object({ name: z.string() })
.and(z.looseRecord(z.string().regex(/_phone$/), z.e164()));
z.record() with enum keys when you only want some of them present: the default is exhaustive — every enum value must appear as a key — use z.partialRecord() instead.z.record() with an enum/literal key schema is exhaustive by default — it mirrors TypeScript's Record<K, V> semantics, not a "maybe has these keys" dictionary.z.partialRecord() the moment you need a subset of enum-keyed fields.z.looseRecord() combined with .and() (intersection) is the pattern for "known field + arbitrary pattern-matched extra fields.".catchall() solves a similar "unknown keys" problem for a fixed-shape object rather than a pure dictionary.Map/Set runtime type instead of a plain object.