如何在Zod中基于其他字段定义字段并保证输出类型正确?
如何在Zod中基于其他字段定义字段并保证输出类型正确?
嘿,看你已经在折腾Zod的Schema扩展来区分不同职业状态了,要实现「根据某个字段的不同值,对应不同的字段结构」还保证TypeScript类型完全准确,Zod的**discriminated union(区分联合类型)**绝对是你要找的工具!它专门处理这种互斥结构的校验和类型推导,比单独写两个Schema再合并靠谱多了。
先给你调整后的完整代码示例(我补全了你没写完的salarieSchema部分,你可以根据实际需求修改):
// 先假设你的基础通用字段Schema是这样的(根据你的代码推测) const baseProfessionalInformationSchema = z.object({ name: z.string(), email: z.string().email(), // 其他所有职业状态都共享的字段... }); // 独立从业者专属Schema const independantSchema = baseProfessionalInformationSchema.extend({ professional_status: z.literal('independant' satisfies ProfessionalStatus), profession: z.enum( Object.keys(PROFESSIONS.INDEPENDANTS) as [ keyof typeof PROFESSIONS.INDEPENDANTS, ...Array<keyof typeof PROFESSIONS.INDEPENDANTS> ] ), date_creation_company: z.string(), }); // 受雇者专属Schema const salarieSchema = baseProfessionalInformationSchema.extend({ professional_status: z.literal('salarie' satisfies ProfessionalStatus), employer_name: z.string(), hire_date: z.string(), // 其他受雇者专属的字段... }); // 核心:用discriminatedUnion把两个Schema合并,指定区分字段是professional_status const professionalInformationSchema = z.discriminatedUnion('professional_status', [ independantSchema, salarieSchema, ]); // 自动推导的类型完全正确,会根据professional_status区分两种结构 type ProfessionalInformation = z.infer<typeof professionalInformationSchema>;
为什么这个方案好用?
- 校验精准:Zod会根据
professional_status的值自动校验对应字段,比如如果状态是independant,就会强制检查date_creation_company,不会要求受雇者的employer_name,反之亦然,避免出现不符合结构的数据。 - 类型安全:TypeScript会自动识别联合类型的分支——当你判断
professional_status === 'independant'时,编辑器会自动提示该对象拥有date_creation_company字段,不会出现类型报错。
另外你原来写的z.enum部分是对的,通过类型断言把对象key转成元组类型,避免了Zod生成宽泛的字符串类型,保证了profession字段只能是PROFESSIONS.INDEPENDANTS的合法key。
如果以后遇到更复杂的字段依赖(比如某个字段可选与否取决于另一个字段),还可以用z.refine做自定义校验,但对于这种完全不同的结构,discriminated union是Zod官方推荐的最优解。
备注:内容来源于stack exchange,提问作者Jeromearsene
相关产品推荐
相关产品推荐

