递归类型
Zod 支持递归模式,这对于验证嵌套数据结构非常有用。
基本递归
使用 z.lazy()
创建递归模式:
ts
import { z } from "zod";
// 定义一个递归的类别结构
type Category = {
name: string;
subcategories: Category[];
};
const Category: z.ZodType<Category> = z.lazy(() =>
z.object({
name: z.string(),
subcategories: z.array(Category),
})
);
// 验证
Category.parse({
name: "食品",
subcategories: [
{
name: "水果",
subcategories: [
{
name: "热带水果",
subcategories: [],
},
],
},
],
}); // 通过
互递归类型
你可以定义多个相互递归的类型:
ts
// 文件系统示例
const FileSystem = z.lazy(() =>
z.object({
type: z.literal("directory"),
children: z.array(z.union([File, FileSystem])),
})
);
const File = z.object({
type: z.literal("file"),
content: z.string(),
});
// 验证
FileSystem.parse({
type: "directory",
children: [
{
type: "file",
content: "hello.txt",
},
{
type: "directory",
children: [
{
type: "file",
content: "world.txt",
},
],
},
],
}); // 通过
JSON 类型
使用递归类型定义 JSON 数据结构:
ts
const literalSchema = z.union([z.string(), z.number(), z.boolean(), z.null()]);
type Literal = z.infer<typeof literalSchema>;
const JsonSchema: z.ZodType<Json> = z.lazy(() =>
z.union([
literalSchema,
z.array(JsonSchema),
z.record(JsonSchema),
])
);
type Json = Literal | { [key: string]: Json } | Json[];
// 验证
JsonSchema.parse({
string: "hello",
number: 42,
array: [1, 2, 3],
object: {
nested: {
data: [true, null, "world"],
},
},
}); // 通过
性能考虑
递归类型可能会影响验证性能,特别是对于深度嵌套的数据:
ts
// 添加最大深度限制
const LimitedCategory = z.lazy(() =>
z.object({
name: z.string(),
subcategories: z.array(LimitedCategory).max(5), // 限制子类别数量
})
);
// 添加最大递归深度
let depth = 0;
const MaxDepthCategory = z.lazy(() => {
if (depth > 3) throw new Error("最大递归深度超出");
depth++;
return z.object({
name: z.string(),
subcategories: z.array(MaxDepthCategory),
});
});
类型推断
TypeScript 可以正确推断递归类型:
ts
const Comment = z.lazy(() =>
z.object({
text: z.string(),
replies: z.array(Comment),
})
);
type Comment = z.infer<typeof Comment>;
// {
// text: string;
// replies: Comment[];
// }
// 使用类型
const comment: Comment = {
text: "父评论",
replies: [
{
text: "子评论",
replies: [],
},
],
};