Capítulo 2 de 61

Chapter 2: Primitives & Coercion

Core Idea

Zod exposes a schema for every JS primitive type, and a parallel z.coerce.* family that converts input to the target type before validating, using the built-in JS constructors (String(), Number(), etc.).

Key Concepts

  • z.string() / z.number() / z.bigint() / z.boolean() / z.symbol() / z.undefined() / z.null(): one schema per JS primitive type.
  • z.coerce.*: coerces input via the matching JS constructor before validating (z.coerce.number() runs Number(input)).
  • Coercion input type: defaults to unknown; pass a generic (z.coerce.string<string>()) to narrow the accepted input type.
  • Boolean coercion caveat: z.coerce.boolean() follows JS truthy/falsy rules, not string parsing — "false" coerces to true because it's a non-empty string.

Code Examples

import * as z from "zod";

// primitive types
z.string();
z.number();
z.bigint();
z.boolean();
z.symbol();
z.undefined();
z.null();

// coercion
const schema = z.coerce.string();
schema.parse("tuna");    // => "tuna"
schema.parse(42);        // => "42"
schema.parse(true);      // => "true"
schema.parse(null);      // => "null"
  • What it demonstrates: primitive schemas validate a type as-is; z.coerce.* schemas convert first, then validate.

Reference Tables

Zod APICoercion applied
z.coerce.string()String(value)
z.coerce.number()Number(value)
z.coerce.boolean()Boolean(value) (truthy/falsy, not string parsing)
z.coerce.bigint()BigInt(value)
z.coerce.date()new Date(value)

Anti-patterns

  • Assuming z.coerce.boolean() parses "false" as false: it doesn't — any non-empty string is truthy in JS, so "false" coerces to true. Use z.transform() or z.pipe() for custom string→boolean logic.

Key Takeaways

  1. Every primitive has a direct schema; reach for z.coerce.* only when the input genuinely needs type conversion (e.g. query strings, form data).
  2. Coercion delegates to native JS constructors — its quirks (especially boolean truthiness) are JS's quirks, not Zod's.
  3. Coerced schemas accept unknown input by default; narrow with a generic type parameter when you know the real input shape.

Connects To

  • Transforms & Pipes: for coercion logic more complex than a native constructor call.
  • String formats: for validating string content (email, URL, UUID) rather than just its type.