Capítulo 29 de 61
Three distinct fallback mechanisms handle "missing or invalid input" differently: .default() short-circuits on undefined with an output-typed value, .prefault() substitutes an input-typed value and still runs the full parse, and .catch() supplies a fallback for any validation error (not just missing input).
.default(value): if input is undefined, immediately returns value — parsing is short-circuited, so the default must match the schema's output type (post-transform)..default(fn): a function re-invoked each time a default is needed (e.g. Math.random), instead of a fixed value..prefault(value): if input is undefined, substitutes value and still runs the full parsing pipeline (transforms, refinements) on it — so the prefault must match the schema's input type, not output..catch(value) / .catch(fn): returns a fallback when validation fails for any reason (not just missing input); the function form receives a context with the caught error/issues.// default: short-circuits, must match OUTPUT type
const a = z.string().transform(val => val.length).default(0);
a.parse(undefined); // => 0 (the raw number 0, transform never runs)
// prefault: substitutes INPUT, still runs the pipeline
const b = z.string().transform(val => val.length).prefault("tuna");
b.parse(undefined); // => 4 ("tuna" is parsed and transformed)
// prefault lets mutating refinements still apply
const c = z.string().trim().toUpperCase().prefault(" tuna ");
c.parse(undefined); // => "TUNA"
const d = z.string().trim().toUpperCase().default(" tuna ");
d.parse(undefined); // => " tuna " (default bypasses trim/uppercase)
// catch: fallback on ANY validation error, not just missing input
const numberWithCatch = z.number().catch(42);
numberWithCatch.parse(5); // => 5
numberWithCatch.parse("tuna"); // => 42 (validation failed, fallback used)
.default() on a schema with a transform, expecting the transform to run on the default: it won't — .default() short-circuits before the transform. Use .prefault() if the default value should go through the same pipeline as real input..default() is for "value is absent" and skips further processing; .prefault() is for "value is absent, but still validate/transform it like real input would be.".catch() is broader than both — it recovers from any failed parse, not just an undefined input..default()'s value must match the output type, .prefault()'s must match the input type..prefault() runs through but .default() bypasses.