TypeScript中使用Yup验证枚举数组报类型错误的正确实现方式
Yup 数字枚举数组校验类型报错解决方案
问题根因
报错来自两个核心问题:
- TypeScript 数字枚举会生成反向映射,直接调用
Object.values(TestEnum)会同时返回枚举的数字值和字符串键,返回结果为[0, 1, "TEST", "NOT_TEST"],直接断言为TestEnum[]既不符合类型事实,也会导致运行时校验逻辑异常。 - 旧版本 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
相关产品推荐
相关产品推荐

