教程 zod tutorial

Objects

Zod 提供了强大的对象验证功能。

基本用法

ts
import { z } from "zod";

const User = z.object({
  username: z.string(),
  age: z.number(),
  email: z.string().email(),
  isAdmin: z.boolean().optional(),
});

type User = z.infer<typeof User>;
// { username: string; age: number; email: string; isAdmin?: boolean }

访问对象属性

使用 .shape 访问对象的属性模式:

ts
const User = z.object({
  username: z.string(),
  age: z.number(),
});

User.shape.username; // 返回字符串模式
User.shape.age; // 返回数字模式

扩展对象

使用 .extend 添加新属性:

ts
const User = z.object({
  username: z.string(),
});

const AdminUser = User.extend({
  isAdmin: z.boolean(),
  permissions: z.array(z.string()),
});

合并对象

使用 .merge 合并两个对象模式:

ts
const BaseUser = z.object({
  id: z.string(),
  username: z.string(),
});

const UserDetails = z.object({
  age: z.number(),
  email: z.string().email(),
});

const FullUser = BaseUser.merge(UserDetails);
// 等同于:
// z.object({
//   id: z.string(),
//   username: z.string(),
//   age: z.number(),
//   email: z.string().email(),
// })

部分选择和忽略

使用 .pick 和 .omit 选择或忽略特定属性:

ts
const User = z.object({
  id: z.string(),
  username: z.string(),
  age: z.number(),
  email: z.string(),
});

// 只选择某些字段
const UserBasics = User.pick({ username: true, age: true });
// { username: string; age: number }

// 忽略某些字段
const UserWithoutId = User.omit({ id: true });
// { username: string; age: number; email: string }

可选字段

使用 .partial 使所有字段变为可选:

ts
const User = z.object({
  username: z.string(),
  age: z.number(),
});

const PartialUser = User.partial();
// { username?: string; age?: number }

// 深度可选
const DeepPartialUser = User.deepPartial();

严格模式

默认情况下,Zod 会剔除未定义的字段。你可以使用 .strict() 禁止额外字段:

ts
const User = z.object({
  username: z.string(),
}).strict();

User.parse({
  username: "bob",
  extra: "field", // 将抛出错误
});

// 或使用 .passthrough() 保留额外字段
const FlexibleUser = z.object({
  username: z.string(),
}).passthrough();

FlexibleUser.parse({
  username: "bob",
  extra: "field", // 将被保留
});

通配符属性

使用 .catchall 定义未知键的类型:

ts
const NumberCache = z.object({
  id: z.string(),
}).catchall(z.number());

// 等同于 { [k: string]: number } & { id: string }

NumberCache.parse({
  id: "xyz123",
  count: 42,
  amount: 123,
}); // 通过