Zod枚举验证时出现TypeScript类型错误的技术咨询
问题描述
现有如下对象定义:
const escortTypeOptions = [ { value: "Nutrition", label: "תזונה" }, { value: "Training", label: "אימונים" }, { value: "Nutrition and Training", label: "תזונה ואימונים" }, ]; const escortTypeValues = escortTypeOptions.map((option) => option.value);
在Zod中定义Schema时使用了以下写法:
z.object({ // ...其他字段 escortType: z.enum([...escortTypeValues], { errorMap: (issue, ctx) => ({ message: '请选择其中一个选项' }) }), });
此时触发TypeScript错误:
No overload matches this call. Overload 1 of 2, '(values: readonly [string, ...string[]], params?: RawCreateParams): ZodEnum<[string, ...string[]]>', gave the following error. Argument of type 'string[]' is not assignable to parameter of type 'readonly [string, ...string[]]'. Source provides no match for required element at position 0 in target. Overload 2 of 2, '(values: [string, ...string[]], params?: RawCreateParams): ZodEnum<[string, ...string[]]>', gave the following error. Argument of type 'string[]' is not assignable to parameter of type '[string, ...string[]]'. Source provides no match for required element at position 0 in target.
尝试给escortTypeValues添加as const断言:
const escortTypeValues = escortTypeOptions.map((option) => option.value) as const;
又出现新错误:
A 'const' assertions can only be applied to references to enum members, or string, number, boolean, array, or object literals.
解决方法
方案1:给原始选项数组添加as const断言
TypeScript无法从map方法的返回值中推导字面量类型,所以需要先固定原始数组的类型为字面量元组:
const escortTypeOptions = [ { value: "Nutrition", label: "תזונה" }, { value: "Training", label: "אימונים" }, { value: "Nutrition and Training", label: "תזונה ואימונים" }, ] as const;
接着提取值类型并生成固定的数组:
type EscortType = typeof escortTypeOptions[number]['value']; const escortTypeValues = escortTypeOptions.map(option => option.value) as readonly EscortType[];
最后在Zod Schema中使用:
z.object({ // ...其他字段 escortType: z.enum(escortTypeValues, { errorMap: (issue, ctx) => ({ message: '请选择其中一个选项' }) }), });
方案2:用z.union结合z.literal替代z.enum
如果不想修改原始数组的断言,可以直接从数组生成联合字面量类型,再构建Zod校验规则:
// 提取联合类型 type EscortType = typeof escortTypeOptions[number]['value']; // 生成对应Zod字面量校验项数组 const escortTypeSchemaItems = escortTypeOptions.map(option => z.literal(option.value)); // 在对象Schema中使用 z.object({ // ...其他字段 escortType: z.union(escortTypeSchemaItems, { errorMap: (issue, ctx) => ({ message: '请选择其中一个选项' }) }), });
方案3:手动定义枚举类型并关联数组
先定义TypeScript枚举,再基于枚举生成选项数组,确保类型与数据完全同步:
enum EscortType { Nutrition = 'Nutrition', Training = 'Training', NutritionAndTraining = 'Nutrition and Training', } // 基于枚举生成选项数组 const escortTypeOptions = [ { value: EscortType.Nutrition, label: "תזונה" }, { value: EscortType.Training, label: "אימונים" }, { value: EscortType.NutritionAndTraining, label: "תזונה ואימונים" }, ]; // Zod中直接使用原生枚举 z.object({ // ...其他字段 escortType: z.nativeEnum(EscortType, { errorMap: (issue, ctx) => ({ message: '请选择其中一个选项' }) }), });
内容的提问来源于stack exchange,提问作者steve123
相关产品推荐
相关产品推荐

