Capítulo 14 de 61

Chapter 14: Unknown, Any & Never

Core Idea

Zod mirrors TypeScript's special types one-to-one: z.any()/z.unknown() accept everything, z.never() accepts nothing.

Key Concepts

  • z.any(): accepts any value; inferred type is any.
  • z.unknown(): accepts any value; inferred type is unknown (safer than any downstream since TS forces a check before use).
  • Object property key requiredness: as a property, z.any()/z.unknown() still requires the key to be present (matching { a: any } in TS) — the key can hold undefined as a value, but can't be omitted unless also .optional().
  • z.never(): no value passes; inferred type is never. Useful for asserting a branch is unreachable or a field must never be provided.

Code Examples

z.any();     // inferred type: any
z.unknown(); // inferred type: unknown

z.object({ a: z.any() }).parse({});                // throws — key "a" missing
z.object({ a: z.any() }).parse({ a: undefined });   // ok — key present, value undefined
z.object({ a: z.any().optional() }).parse({});      // ok — key allowed to be absent

z.never(); // inferred type: never
  • What it demonstrates: z.any()/z.unknown() don't imply the key is optional — that still needs an explicit .optional().

Anti-patterns

  • Assuming z.any() makes an object key optional: it doesn't; the key must still be present unless you also chain .optional().

Key Takeaways

  1. Prefer z.unknown() over z.any() when the value must be checked/narrowed before use — unknown forces that in TypeScript, any doesn't.
  2. A required z.any()/z.unknown() key still needs the key to exist in the object, even if its value is undefined.
  3. z.never() is a useful sentinel for "this field must not exist" or "this union branch is exhaustive."

Connects To

  • Optionals: to actually allow a key to be missing, not just any-typed.
  • Objects: where key-presence-vs-value-type distinctions matter most.