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

TypeScript中使用Yup验证枚举数组报类型错误的正确实现方式

Yup 数字枚举数组校验类型报错解决方案

问题根因

报错来自两个核心问题:

  1. TypeScript 数字枚举会生成反向映射,直接调用Object.values(TestEnum)会同时返回枚举的数字值和字符串键,返回结果为[0, 1, "TEST", "NOT_TEST"],直接断言为TestEnum[]既不符合类型事实,也会导致运行时校验逻辑异常。
  2. 旧版本 Yup 的yup.array()方法会根据传入的内部 schema 自动窄化数组元素类型,当内部使用yup.mixed()时,类型推断会错误地将元素类型收敛到枚举的单个成员,最终出现类型不匹配的报错。

可直接运行的正确实现

适用于 Yup v0.32.x 主流版本

优先使用和枚举类型匹配的基础 schema(数字枚举用yup.number(),字符串枚举用yup.string()),提前过滤掉数字枚举反向映射生成的字符串键,从根源避免类型和运行时错误:

export enum TestEnum {
  TEST = 0,
  NOT_TEST = 1,
}

export interface SampleDTO {
  testEnum: TestEnum[];
}

// 过滤反向映射生成的字符串键,得到纯枚举值数组,同时做类型守卫收窄类型
const validEnumValues = Object.values(TestEnum).filter(
  (val): val is TestEnum => typeof val === 'number'
);

export const sampleDtoSchema: SchemaOf<SampleDTO> = yup.object({
  testEnum: yup
    .array(
      yup
        .number<TestEnum>()
        .oneOf(validEnumValues)
        .required()
    )
    .ensure(),
});

如果是字符串枚举,不需要做过滤,直接取Object.values(Enum)作为oneOf参数,搭配yup.string<EnumType>()使用即可。

兼容旧版本 Yup 的写法

如果上述写法在你使用的旧版本 Yup 中依然报类型错误,可以给yup.array()显式传入泛型参数,绕开内部 schema 的类型窄化逻辑:

export const sampleDtoSchema: SchemaOf<SampleDTO> = yup.object({
  testEnum: yup
    .array<TestEnum>(
      yup
        .mixed<TestEnum>()
        .oneOf(validEnumValues)
        .required()
    )
    .ensure(),
});

Yup v1.x 简化写法

v1 版本原生提供了枚举校验方法,不需要手动处理枚举值提取:

export const sampleDtoSchema: SchemaOf<SampleDTO> = yup.object({
  testEnum: yup.array(yup.enum(TestEnum).required()).ensure(),
});

注意事项

  • 不要直接对Object.values(数字枚举)做类型断言,否则会导致字符串键被加入合法值范围,运行时出现预期外的校验失败
  • ensure()方法会自动将null/undefined的输入转换为空数组,数组层不需要额外加required(),仅需对数组内元素做必填校验即可

内容的提问来源于stack exchange,提问作者Przemek Wit

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.31 23:39:21