You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何使用Zod验证生成器及其输出?

使用Zod验证生成器及其输出的方案

Zod本身没有内置的z.generator()方法,但可以通过两种核心方式实现生成器的验证:一是校验生成器函数的返回类型,确保它返回符合要求的生成器;二是校验生成器产出的每一个值,实现快速失败。

1. 验证生成器函数的返回类型

用Zod的z.custom()自定义生成器类型的校验逻辑,确保函数返回的是合法生成器对象。

import { z } from "zod";

// 定义生成器产出值的Schema
const SomeZodSchema = z.object({
  type: z.enum(["progress", "result", "error"]),
  data: z.union([z.number(), z.string(), z.object({ message: z.string() })])
});

// 自定义生成器校验规则
const GeneratorSchema = z.custom<Generator<z.infer<typeof SomeZodSchema>>>(
  (val) => {
    return typeof val === "object" && val !== null && Symbol.iterator in val && typeof val.next === "function";
  },
  { message: "值必须是一个生成器对象" }
);

// 定义作业函数的Schema
const JobFunction = z
  .function()
  .args() // 有参数可在此定义参数Schema
  .returns(GeneratorSchema);

// 合法作业函数示例
const validJob = function* () {
  yield { type: "progress", data: 50 };
  yield { type: "result", data: "完成" };
};

JobFunction.parse(validJob); // 验证通过

// 非法函数示例(返回非生成器)
const invalidJob = () => "不是生成器";
JobFunction.parse(invalidJob); // 抛出ZodError

2. 验证生成器产出的每个值

创建包装函数,在生成器产出值时自动用Zod校验,确保每一步产出都符合Schema,实现快速失败。

import { z } from "zod";

const SomeZodSchema = z.object({
  type: z.enum(["progress", "result", "error"]),
  data: z.union([z.number(), z.string(), z.object({ message: z.string() })])
});

// 包装生成器,自动校验产出值
function validateGenerator<T>(generator: Generator<T>, schema: z.ZodSchema<T>) {
  return function* () {
    for (const value of generator) {
      // 校验失败立即抛出错误
      const validated = schema.parse(value);
      yield validated;
    }
  } as Generator<z.infer<typeof schema>>;
}

// 作业函数示例
const myJob = function* () {
  yield { type: "progress", data: 50 };
  yield { type: "result", data: "完成" };
  // 下面这行会在产出时触发校验失败
  // yield { type: "invalid", data: "错误类型" };
};

// 开启校验的生成器
const validatedGenerator = validateGenerator(myJob(), SomeZodSchema);

// 遍历生成器,校验不通过时立即抛错
for (const item of validatedGenerator) {
  console.log(item);
}

3. 结合两种方式:验证函数+自动校验产出

同时确保作业函数返回生成器,且每个产出值合法,把两种方式结合起来:

import { z } from "zod";

const SomeZodSchema = z.object({
  type: z.enum(["progress", "result", "error"]),
  data: z.union([z.number(), z.string(), z.object({ message: z.string() })])
});

const GeneratorSchema = z.custom<Generator<z.infer<typeof SomeZodSchema>>>(
  (val) => typeof val === "object" && val !== null && Symbol.iterator in val && typeof val.next === "function",
  { message: "必须返回生成器对象" }
);

const JobFunction = z
  .function()
  .args()
  .returns(GeneratorSchema);

// 包装作业函数,返回带校验的生成器
function createValidatedJob(jobFn: z.infer<typeof JobFunction>) {
  JobFunction.parse(jobFn); // 先验证函数本身
  return function* () {
    const generator = jobFn();
    for (const value of generator) {
      yield SomeZodSchema.parse(value);
    }
  };
}

// 合法作业函数
const validJob = function* () {
  yield { type: "progress", data: 75 };
  yield { type: "result", data: "任务完成" };
};

const validatedJob = createValidatedJob(validJob);

// 遍历产出,自动校验
for (const item of validatedJob()) {
  console.log(item);
}

可观察对象的补充说明

如果用RxJS等可观察对象库,验证逻辑类似:通过pipe(map(value => schema.parse(value)))校验每个发射的值,非法值会立即抛出错误,同样符合快速失败的需求。

内容的提问来源于stack exchange,提问作者GregRos

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.28 11:42:40