如何让Zod基于枚举属性而非值校验?原因与解决方法
问题场景
我正在使用Zod Schema校验一个包含枚举字段的对象,代码如下:
enum Colour { red = 'Red', blue = 'Blue', } const schema = z.object({ colour: z.nativeEnum(Colour), });
从API获取的颜色输入值为'red'或'blue',希望用上述Schema校验,但当前z.nativeEnum校验的是枚举中的大写值(如'Red')而非枚举属性(如'red'):
enum Colour { red = 'Red', blue = 'Blue', } const schema = z.object({ colour: z.nativeEnum(Colour), }); const rawInput1 = { colour: 'red' // 应被判定为有效 }; const parsedInput1 = schema.parse(rawInput1); // 校验失败 const rawInput2 = { colour: 'Red' // 应被判定为无效 }; const parsedInput2 = schema.parse(rawInput2); // 校验通过
我需要让Zod基于枚举属性而非值进行校验,并且解析对象后,要用colour变量通过枚举索引获取其字符串值(即Colour[parsedInput1.colour]),若colour为字符串值则无法实现该操作。
问题原因
z.nativeEnum(Colour)的核心逻辑是校验输入值是否属于枚举的值集合(即'Red'、'Blue')。TypeScript的字符串枚举编译后会生成包含双向映射的对象(键→值、值→键),但Zod的nativeEnum方法默认以枚举的值作为校验范围,因此只会允许枚举定义中=右侧的内容通过校验。
解决方案
方法1:提取枚举键创建Zod枚举校验器
通过Object.keys提取枚举的键数组,再用z.enum创建校验器,直接校验输入是否为枚举的合法键:
enum Colour { red = 'Red', blue = 'Blue', } // 提取枚举的键并断言为合法键类型 const ColourKeys = Object.keys(Colour) as Array<keyof typeof Colour>; const schema = z.object({ colour: z.enum(ColourKeys), }); // 测试 const rawInput1 = { colour: 'red' }; const parsedInput1 = schema.parse(rawInput1); // 校验通过 console.log(Colour[parsedInput1.colour]); // 输出 'Red' const rawInput2 = { colour: 'Red' }; schema.parse(rawInput2); // 校验失败,符合预期
方法2:使用refine自定义校验逻辑
如果需要更灵活的校验,可以用z.string().refine来检查输入是否是枚举的合法键:
enum Colour { red = 'Red', blue = 'Blue', } const schema = z.object({ colour: z.string().refine( val => Object.keys(Colour).includes(val), { message: 'colour必须是red或blue' } ), }); // 测试效果和方法1一致
内容的提问来源于stack exchange,提问作者Lemour
相关产品推荐
相关产品推荐

