You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.10 21:40:30