Capítulo 16 de 61
Zod provides TypeScript-utility-type-inspired methods (.extend(), .pick(), .omit(), .partial(), .required()) for deriving new object schemas from an existing one, plus spread syntax as a tsc-cheaper alternative to .extend().
.extend({...}): adds fields to a schema; if a key already exists, the new field overrides it. Throws when used on a schema carrying refinements.z.object({ ...Base.shape, newField: z.string() }) achieves the same result using plain JS, works identically in Zod and Zod Mini, and avoids the quadratic tsc cost of chained .extend() calls..safeExtend({...}): like .extend(), but rejects overriding a field with a non-assignable schema (type-checked at compile time), and — unlike .extend() — works on schemas with refinements, inheriting them..pick({...}) / .omit({...}): derive a schema with only the given keys, or all keys except the given ones (mirrors TS Pick/Omit)..partial() / .partial({...}): makes all (or selected) fields optional (via .optional())..exactPartial(): like .partial() but wraps fields in .exactOptional() instead of .optional().z.deepPartial(schema): recursively makes nested objects/arrays/tuples/unions/records partial too, not just the top level; a discriminated union degrades to a plain union since an optional discriminant breaks fast-path lookup; throws on schemas with their own refinement..required() / .required({...}): the inverse of .partial() — makes all or selected fields required.const Recipe = z.object({
title: z.string(),
description: z.string().optional(),
ingredients: z.array(z.string()),
});
const JustTheTitle = Recipe.pick({ title: true });
const RecipeNoDescription = Recipe.omit({ description: true });
const PartialRecipe = Recipe.partial();
const RecipeRequiredDescription = Recipe.required({ description: true });
// extending a schema that has a refinement — .extend() would throw, .safeExtend() works
const Base = z.object({ a: z.string(), b: z.string() })
.refine(user => user.a === user.b);
const Extended = Base.safeExtend({ a: z.string().min(10) }); // inherits the refinement
.safeExtend() as the refinement-safe alternative to .extend()..extend() calls on large schemas: each call is tsc-expensive and the cost compounds quadratically due to a TypeScript limitation — prefer spread syntax ({ ...A.shape, ...B.shape }) for merging multiple schemas..extend() on a schema with a .refine(): throws; use .safeExtend() instead, which both allows it and preserves the refinement..extend() for merging schemas — it's language-native, works the same in Zod and Zod Mini, and avoids compile-time cost blowup on chains..safeExtend() is the type-safe, refinement-preserving version of .extend() — use it whenever the base schema might carry a .refine().z.deepPartial() recurses through the whole schema tree, unlike .partial(), but changes the semantics of discriminated unions (they lose their fast-path discriminant)..extend() throws on refined schemas and .safeExtend() doesn't.