如何在TypeScript中为条件类型验证创建单个Zod Schema?
用单个Zod Schema验证带类型专属字段的RichText类型
当然可以,你可以利用Zod的discriminatedUnion特性,创建一个单个的Schema,实现和TypeScript的RichText类型完全匹配的验证逻辑,无需手动判断使用哪个子Schema。
问题回顾
你定义的TypeScript类型如下:
// 用于类型专属字段的索引类型 interface RichTextMap { text?: { text: string }; equation?: { equation: string }; mention?: { mention: string }; } // 带索引类型的主RichText接口 interface RichTextBase { type: "text" | "mention" | "equation"; annotations: any; plain_text: string; href: string | null; } type RichText = RichTextBase & (RichTextMap[RichTextBase["type"]] & {});
符合该类型的示例对象:
const text = { type: "text", annotations: {}, plain_text: "", href: null, text: { text: "" } } const mention = { type: "mention", annotations: {}, plain_text: "", href: null, mention: { mention: "" } }
你当前的方案创建了三个独立的Schema,需要手动判断使用场景,无法像RichText类型那样统一处理所有情况。
解决方案
使用discriminatedUnion基于type字段做鉴别,自动匹配对应的专属字段验证规则:
import { z } from "zod"; // 定义公共字段的基础Schema const RichTextBaseSchema = z.object({ type: z.enum(["text", "mention", "equation"]), annotations: z.object({}).passthrough(), plain_text: z.string(), href: z.string().url().nullable(), }); // 为每个类型定义带固定type字面量的子Schema const TextSchema = RichTextBaseSchema.extend({ type: z.literal("text"), text: z.object({ text: z.string() }), }); const MentionSchema = RichTextBaseSchema.extend({ type: z.literal("mention"), mention: z.object({ mention: z.string() }), }); const EquationSchema = RichTextBaseSchema.extend({ type: z.literal("equation"), equation: z.object({ equation: z.string() }), }); // 组合成单个鉴别联合Schema const RichTextSchema = z.discriminatedUnion("type", [ TextSchema, MentionSchema, EquationSchema, ]); // 验证测试 RichTextSchema.parse(text); // 验证通过 RichTextSchema.parse(mention); // 验证通过 // 如果传入不符合的对象(比如type为text但带mention字段)会抛出验证错误
核心逻辑说明
discriminatedUnion是Zod专门处理鉴别联合类型的方法,它会根据指定的鉴别字段(这里是type)自动选择对应的验证规则- 每个子Schema通过
extend将type固定为字面量值,确保Zod能精准匹配 - 最终的
RichTextSchema可以直接验证所有符合RichText类型定义的对象,无需额外分支判断
内容的提问来源于stack exchange,提问作者Pavlo Sobchuk
相关产品推荐
相关产品推荐

