【发布时间】:2020-10-13 10:27:45
【问题描述】:
我有一个const enum,如下所示:
const enum Color {
Red = "red",
Green = "green",
Blue = "blue"
}
我还有一些来自外部的字符串(比如colorString)。它的值应该是"red",或"green",或"blue",但不确定。我想验证它并在无效值的情况下抛出。
对于“转换”,我可以这样做:
const color: Color = colorString as Color;
这将字符串“转换”为枚举,但不对其进行验证。如果constString === "purple" 在运行时不会出错。为了验证,我可以这样做:
function stringToColor(colorString: string): Color {
switch (colorString) {
case Color.Red:
case Color.Green:
case Color.Blue:
return colorString; // no need to do 'as', TS knows that colorString is valid Color enum value
default:
throw new Error(`Invalid color ${colorString}.`);
}
}
这个“转换”字符串为枚举并对其进行验证,但它有点冗长且容易出错。例如,如果我向 Color 枚举添加新值,我必须在 stringToColor 函数中向 switch 添加新的 case 语句,以便我的代码正常运行。
Afaik,常量枚举仅在编译时存在,并在运行时被完全擦除为纯字符串。所以没有任何真正的转换。另外,我不能做Object.values(Color),因为Color 是const enum 并且在运行时不存在。我真正需要的是:
- 在运行时检查字符串是否具有指定(有效)值之一;
- 在编译时告诉 TypeScript 字符串可以表示为枚举。
另一种解决方案是将所有有效值保留在这样的对象中:
const colors: { readonly [color in Color]: color } = {
[Color.Red]: Color.Red,
[Color.Green]: Color.Green,
[Color.Blue]: Color.Blue,
};
这里的好处是这个对象必须包含每个枚举值的属性(不像Color[])。如果我向枚举添加一个新值,但忘记将其添加到 colors 对象,如果将在编译时失败。因此,它比写一打case 语句更不容易出错。然后我可以这样做:
function stringToColor(colorString: string): Color | undefined {
return Object.values(colors).find((value) => colorString === value);
}
如果值无效,则返回undefined,这是可以接受的。
但是,我想知道是否有更简洁和更优雅的解决方案。
【问题讨论】:
标签: typescript enums