TypeScript中多枚举组成联合类型出现TS2345错误该如何解决?
报错原因
这个报错是TypeScript枚举的名义类型特性和Array.includes的内置类型定义共同导致的:
- TypeScript 中的枚举属于名义类型(nominal type),即便是结构/取值完全兼容的两个枚举,TS也会将它们判定为完全独立的不兼容类型,因此
EnumB类型的值默认不能直接传入要求EnumA类型的入参位置。 Array<T>.includes的官方类型定义中,第一个入参要求必须是数组元素类型T,你的代码里Object.values(EnumA)返回的数组元素类型是EnumA,而se.type是EnumA | EnumB联合类型,TS认为该值存在是EnumB的可能,不符合入参类型要求,因此抛出TS2345错误。
解决方案
下面是三种常用的修复方案,你可以根据业务场景选择:
方案1:临时类型断言
如果确定当前逻辑只是判断取值是否在EnumA的范围内,运行时逻辑不会出错,可以直接给入参加类型断言绕过TS校验:
const foo = (seArray: SomeEntity[]) => { seArray.forEach((se) => { Object.values(EnumA).includes(se.type as EnumA) }) }
方案2:转成字符串数组判断
因为你的枚举是字符串枚举,取值本质都是字符串,可以先把枚举值数组转成string[]类型,includes就可以接受所有字符串类型的入参:
const foo = (seArray: SomeEntity[]) => { seArray.forEach((se) => { (Object.values(EnumA) as string[]).includes(se.type) }) }
方案3:封装类型守卫(推荐)
如果需要复用判断逻辑,并且希望后续代码可以自动收窄类型,可以封装专用的类型守卫函数:
function isEnumA(value: EnumA | EnumB): value is EnumA { return Object.values(EnumA).includes(value as EnumA) } const foo = (seArray: SomeEntity[]) => { seArray.forEach((se) => { if (isEnumA(se.type)) { // 该分支内TS会自动将se.type收窄为EnumA类型,不需要额外断言 } }) }
方案4:用as const替代枚举(根本解决)
如果不需要枚举的名义类型隔离特性,建议用as const定义常量集合+类型别名替代枚举,就不会出现同类类型不兼容问题:
export const EnumA = { A: 'a' } as const export type EnumA = typeof EnumA[keyof typeof EnumA] export const EnumB = { A: 'b' } as const export type EnumB = typeof EnumB[keyof typeof EnumB]
内容的提问来源于stack exchange,提问作者HelloWorld
相关产品推荐
相关产品推荐

