NodeJS Typescript,带有字符串和数字的枚举

nuypyhwy  于 2023-10-17  发布在  Node.js
关注(0)|答案(2)|浏览(158)

我有一个接口,

interface mathTest {
   mathAction: MathActionEnum;
}

这样做的原因是,我希望这个属性只有下面枚举中的一个特定值。

enum MathActionEnum {
    'byOne' = 1,
    'byTwo' = 2,
    'byFour' = 4,
    'byEight' = 8,
}

假设mathAction = 'byOne'->从API响应接收。

场景一:做一个算术运算,我需要数值:let result: number = amount / MathActionEnum[mathAction]但是我得到一个错误:

算术运算的右侧必须是“any”、“number”、“bigint”或枚举类型
这是一个数字,但我仍然需要用Number(MathActionEnum[mathAction])来转换它,以消 debugging 误。

场景二:相等性检查,我需要字符串值:if (mathAction === MathActionEnum[MathActionEnum.byOne])但是我得到一个错误:

此条件将始终返回“false”,因为类型“MathematicEnum”和“string”没有重叠
这就说得通了
我有点迷路了,有没有一种方法可以像我期望的那样语法化它?也许我需要用不同的方式来定义事物。谢谢

plupiseo

plupiseo1#

TypeScript枚举绝对不适合任何类型的键值Map。其目的是拥有一组唯一可识别的标签,但标签是它的终点。虽然它们可能确实在引擎盖下有一个数字表示,但它们并不打算用作键值存储。你将不得不强制转换它来“提取数字”,然后类型只是number,所以你有效地击败了枚举的目的。
出于所有意图和目的,将它们视为没有有用值的键:

const MathActionEnum = Object.freeze({
  byOne: Symbol(),
  byTwo: Symbol(),
  byFour: Symbol(),
  byEight: Symbol(),
})

请考虑更新的替代方案const assertion。它们将为您提供键和值的类型安全:

const MathActions = {
  'byOne': 1,
  'byTwo': 2,
  'byFour': 4,
  'byEight': 8,
} as const

type MathAction = keyof typeof MathActions

type MathActionValue = typeof MathActions[MathAction]

你可以在键和值上获得完全的类型安全:

const example = (action: MathAction) => {
    return 2 * MathActions[action]
}

example('byOne')

// compile error, not a valid key
example('foo')

 // -------------
const example2 = (actionValue: MathActionValue) => {
    return 2 * actionValue
}

example2(4)

// compile error, not a valid value
example2(19)

您甚至可以添加类型Assert来检查任意值是否是键或值:

const isAction = (action: string): action is MathAction => {
    return Object.keys(MathActions).includes(action)
}
isAction

const isActionValue = (actionValue: number): actionValue is MathActionValue => {
    return Object.values(MathActions).includes(actionValue as any)
}

您甚至可以为键和值获得IDE自动完成功能:

这里有一个Playground

n3ipq98p

n3ipq98p2#

Typescript不公开正确的枚举类型(通过变通方法解决了这个问题)它只是过滤掉非数字值。

Object.values(yourTsEnum).filter((item : any) => /^([0-9]*)$/i.test(String(item))).map(item => Number(item))

相关问题