Capítulo 13 de 61

Chapter 13: Optional, Exact Optional, Nullable & Nullish

Core Idea

Zod has four distinct wrapper modifiers for "this value might be missing" — optional, exact-optional, nullable, and nullish — each mapping to a different TypeScript absence semantic.

Key Concepts

  • z.optional(schema) / schema.optional(): allows the value to be undefined (key can be present-with-undefined or absent). Returns a ZodOptional; .unwrap() gets the inner schema back (Zod Mini: .def.innerType).
  • z.exactOptional(schema) / schema.exactOptional(): allows the key to be absent, but not explicitly set to undefined — matches TypeScript's exactOptionalPropertyTypes semantics.
  • z.nullable(schema) / schema.nullable(): allows the value to be null specifically (not undefined). Returns a ZodNullable, unwrappable the same way.
  • z.nullish(schema): shorthand for optional and nullable combined — accepts undefined, null, or the underlying type.

Code Examples

z.optional(z.literal("yoda"));       // undefined | "yoda"
z.nullable(z.literal("yoda"));       // null | "yoda"
z.nullish(z.literal("yoda"));        // undefined | null | "yoda"

const User = z.object({ name: z.string().exactOptional() });
User.parse({});                  // ok — key absent
User.parse({ name: "yoda" });    // ok
User.parse({ name: undefined }); // throws — key present but undefined
  • What it demonstrates: the difference between "optional" (undefined allowed) and "exact optional" (key must be truly absent, not undefined).

Anti-patterns

  • Using .optional() when you mean exactOptionalPropertyTypes semantics: .optional() accepts an explicit { name: undefined }; if your TS config has exactOptionalPropertyTypes: true and you want to match it exactly, use .exactOptional() instead.
  • Confusing nullable and optional: null and undefined are different values in JS — .nullable() alone does not accept a missing key or undefined.

Key Takeaways

  1. Pick the modifier that matches the actual absence semantics you need: undefined (optional), null (nullable), either (nullish), or "key truly absent" (exact optional).
  2. .unwrap() (or .def.innerType in Zod Mini) recovers the original schema from any of these wrappers.
  3. exactOptional exists specifically to align with TypeScript's exactOptionalPropertyTypes compiler option — reach for it in codebases that enable that flag.

Connects To

  • Defaults & Prefaults: for supplying a fallback value instead of just allowing absence.
  • Objects: these modifiers are most often applied to object property schemas.