Zod如何基于两个鉴别字段实现payload类型区分?
基于Zod中多字段组合鉴别payload类型的解决方案
Zod的discriminatedUnion确实仅支持单个鉴别字段,但可以通过以下两种方案实现多字段组合的payload类型鉴别:
方案一:定义组合对应的完整Schema并合并为Union
先修正并完善基础枚举与各组合的Schema:
enum Action { CREATE = 'create' } enum ObjectType { Potatoe = 'potatoe', Tomatoe = 'tomatoe' } // 定义每个(action, objectType)组合对应的完整对象Schema const CreatePotatoSchema = z.object({ action: z.literal(Action.CREATE), objectType: z.literal(ObjectType.Potatoe), payload: z.object({ weight: z.number() // 对应Potatoe的CREATE操作payload结构 }) }); const CreateTomatoSchema = z.object({ action: z.literal(Action.CREATE), objectType: z.literal(ObjectType.Tomatoe), payload: z.object({ ripeness: z.string() // 对应Tomatoe的CREATE操作payload结构 }) }); // 合并为Union Schema export const TestSchema = z.union([CreatePotatoSchema, CreateTomatoSchema]);
这种方式直接为每个字段组合定义完整的Schema,Zod会自动匹配对应的结构,同时正确推断payload的类型。
方案二:派生虚拟鉴别字段(适合多组合场景)
如果字段组合数量较多,可以通过派生虚拟鉴别字段的方式复用discriminatedUnion:
enum Action { CREATE = 'create' } enum ObjectType { Potatoe = 'potatoe', Tomatoe = 'tomatoe' } // 定义基础公共字段Schema const BaseSchema = z.object({ action: z.nativeEnum(Action), objectType: z.nativeEnum(ObjectType) }); // 按`action-objectType`组合映射对应的payload Schema const payloadSchemas = { 'create-potatoe': z.object({ weight: z.number() }), 'create-tomatoe': z.object({ ripeness: z.string() }) } as const; // 派生虚拟鉴别字段并创建discriminatedUnion export const TestSchema = BaseSchema .transform(data => ({ ...data, type: `${data.action}-${data.objectType}` as const })) .pipe( z.discriminatedUnion('type', Object.entries(payloadSchemas).map(([type, payloadSchema]) => z.object({ type: z.literal(type), payload: payloadSchema }).merge(BaseSchema) ) ) );
该方案通过将action和objectType组合成虚拟的type字段,实现了discriminatedUnion的使用,适合组合数量多、需要统一维护的场景。
内容的提问来源于stack exchange,提问作者coler-j
相关产品推荐
相关产品推荐

