Objects
// all properties are required by default
const Dog = z.object({
name: z.string(),
age: z.number(),
});
// extract the inferred type like this
type Dog = z.infer<typeof Dog>;
// equivalent to:
type Dog = {
name: string;
age: number;
};// all properties are required by default
const Dog = z.object({
name: z.string(),
age: z.number(),
});
// extract the inferred type like this
type Dog = z.infer<typeof Dog>;
// equivalent to:
type Dog = {
name: string;
age: number;
};.shape
Use .shape to access the schemas for a particular key.
Dog.shape.name; // => string schema
Dog.shape.age; // => number schemaDog.shape.name; // => string schema
Dog.shape.age; // => number schema.keyof
Use .keyof to create a ZodEnum schema from the keys of an object schema.
const keySchema = Dog.keyof();
keySchema; // ZodEnum<["name", "age"]>const keySchema = Dog.keyof();
keySchema; // ZodEnum<["name", "age"]>.extend
You can add additional fields to an object schema with the .extend method.
const DogWithBreed = Dog.extend({
breed: z.string(),
});const DogWithBreed = Dog.extend({
breed: z.string(),
});You can use .extend to overwrite fields! Be careful with this power!
.merge
Equivalent to A.extend(B.shape).
const BaseTeacher = z.object({ students: z.array(z.string()) });
const HasID = z.object({ id: z.string() });
const Teacher = BaseTeacher.merge(HasID);
type Teacher = z.infer<typeof Teacher>; // => { students: string[], id: string }const BaseTeacher = z.object({ students: z.array(z.string()) });
const HasID = z.object({ id: z.string() });
const Teacher = BaseTeacher.merge(HasID);
type Teacher = z.infer<typeof Teacher>; // => { students: string[], id: string }If the two schemas share keys, the properties of B overrides the property of A. The returned schema also inherits the "unknownKeys" policy (strip/strict/passthrough) and the catchall schema of B.
.pick/.omit
Inspired by TypeScript's built-in Pick and Omit utility types, all Zod object schemas have .pick and .omit methods that return a modified version. Consider this Recipe schema:
const Recipe = z.object({
id: z.string(),
name: z.string(),
ingredients: z.array(z.string()),
});const Recipe = z.object({
id: z.string(),
name: z.string(),
ingredients: z.array(z.string()),
});To only keep certain keys, use .pick .
const JustTheName = Recipe.pick({ name: true });
type JustTheName = z.infer<typeof JustTheName>;
// => { name: string }const JustTheName = Recipe.pick({ name: true });
type JustTheName = z.infer<typeof JustTheName>;
// => { name: string }To remove certain keys, use .omit .
const NoIDRecipe = Recipe.omit({ id: true });
type NoIDRecipe = z.infer<typeof NoIDRecipe>;
// => { name: string, ingredients: string[] }const NoIDRecipe = Recipe.omit({ id: true });
type NoIDRecipe = z.infer<typeof NoIDRecipe>;
// => { name: string, ingredients: string[] }.partial
Inspired by the built-in TypeScript utility type Partial, the .partial method makes all properties optional.
Starting from this object:
const user = z.object({
email: z.string(),
username: z.string(),
});
// { email: string; username: string }const user = z.object({
email: z.string(),
username: z.string(),
});
// { email: string; username: string }We can create a partial version:
const partialUser = user.partial();
// { email?: string | undefined; username?: string | undefined }const partialUser = user.partial();
// { email?: string | undefined; username?: string | undefined }You can also specify which properties to make optional:
const optionalEmail = user.partial({
email: true,
});
/*
{
email?: string | undefined;
username: string
}
*/const optionalEmail = user.partial({
email: true,
});
/*
{
email?: string | undefined;
username: string
}
*/.deepPartial
The .partial method is shallow — it only applies one level deep. There is also a "deep" version:
const user = z.object({
username: z.string(),
location: z.object({
latitude: z.number(),
longitude: z.number(),
}),
strings: z.array(z.object({ value: z.string() })),
});
const deepPartialUser = user.deepPartial();
/*
{
username?: string | undefined,
location?: {
latitude?: number | undefined;
longitude?: number | undefined;
} | undefined,
strings?: { value?: string}[]
}
*/const user = z.object({
username: z.string(),
location: z.object({
latitude: z.number(),
longitude: z.number(),
}),
strings: z.array(z.object({ value: z.string() })),
});
const deepPartialUser = user.deepPartial();
/*
{
username?: string | undefined,
location?: {
latitude?: number | undefined;
longitude?: number | undefined;
} | undefined,
strings?: { value?: string}[]
}
*/Important limitation: deep partials only work as expected in hierarchies of objects, arrays, and tuples.
.required
Contrary to the .partial method, the .required method makes all properties required.
Starting from this object:
const user = z
.object({
email: z.string(),
username: z.string(),
})
.partial();
// { email?: string | undefined; username?: string | undefined }const user = z
.object({
email: z.string(),
username: z.string(),
})
.partial();
// { email?: string | undefined; username?: string | undefined }We can create a required version:
const requiredUser = user.required();
// { email: string; username: string }const requiredUser = user.required();
// { email: string; username: string }You can also specify which properties to make required:
const requiredEmail = user.required({
email: true,
});
/*
{
email: string;
username?: string | undefined;
}
*/const requiredEmail = user.required({
email: true,
});
/*
{
email: string;
username?: string | undefined;
}
*/.passthrough
By default Zod object schemas strip out unrecognized keys during parsing.
const person = z.object({
name: z.string(),
});
person.parse({
name: "bob dylan",
extraKey: 61,
});
// => { name: "bob dylan" }
// extraKey has been strippedconst person = z.object({
name: z.string(),
});
person.parse({
name: "bob dylan",
extraKey: 61,
});
// => { name: "bob dylan" }
// extraKey has been strippedInstead, if you want to pass through unknown keys, use .passthrough() .
person.passthrough().parse({
name: "bob dylan",
extraKey: 61,
});
// => { name: "bob dylan", extraKey: 61 }person.passthrough().parse({
name: "bob dylan",
extraKey: 61,
});
// => { name: "bob dylan", extraKey: 61 }.strict
By default Zod object schemas strip out unrecognized keys during parsing. You can disallow unknown keys with .strict() . If there are any unknown keys in the input, Zod will throw an error.
const person = z
.object({
name: z.string(),
})
.strict();
person.parse({
name: "bob dylan",
extraKey: 61,
});
// => throws ZodErrorconst person = z
.object({
name: z.string(),
})
.strict();
person.parse({
name: "bob dylan",
extraKey: 61,
});
// => throws ZodError.strip
You can use the .strip method to reset an object schema to the default behavior (stripping unrecognized keys).
.catchall
You can pass a "catchall" schema into an object schema. All unknown keys will be validated against it.
const person = z
.object({
name: z.string(),
})
.catchall(z.number());
person.parse({
name: "bob dylan",
validExtraKey: 61, // works fine
});
person.parse({
name: "bob dylan",
validExtraKey: false, // fails
});
// => throws ZodErrorconst person = z
.object({
name: z.string(),
})
.catchall(z.number());
person.parse({
name: "bob dylan",
validExtraKey: 61, // works fine
});
person.parse({
name: "bob dylan",
validExtraKey: false, // fails
});
// => throws ZodErrorUsing .catchall() obviates .passthrough() , .strip() , or .strict(). All keys are now considered "known".