有没有办法使 TypeScript 枚举与 JSON 中的字符串兼容?
例如:
enum Type { NEW, OLD }
interface Thing { type: Type }
let thing:Thing = JSON.parse('{"type": "NEW"}');
alert(thing.type == Type.NEW); // false
我希望 thing.type == Type.NEW
成立。更具体地说,我希望能够指定enum
值为字符串而不是数字。
我知道我可以使用 thing.type.toString() == Type[Type.NEW]
,但这很麻烦,似乎会使枚举类型注释变得混乱和误导性,这违背了它的目的。JSON 技术上并没有提供有效的枚举值,所以我不应该将属性类型定义为枚举。
因此,我现在正在使用一个包含静态常量的字符串类型:
const Type = { NEW: "NEW", OLD: "OLD" }
interface Thing { type: string }
let thing:Thing = JSON.parse('{"type": "NEW"}');
alert(thing.type == Type.NEW); // true
这样做可以得到我想要的用法,但类型注释 string
太广泛且容易出错。
作为 JavaScript 的超集,没有字符串枚举有些令人惊讶。我错过了什么吗?还有其他实现方式吗?
更新 TS 1.8
使用字符串字面量类型是另一种选择(感谢 @basaret),但要获得所需的类似枚举的用法(如上所述),需要将值定义两次:一次作为字符串字面量类型,一次作为值(常量或命名空间):
type Type = "NEW" | "OLD";
const Type = {
NEW: "NEW" as Type,
OLD: "OLD" as Type
}
interface Thing { type: Type }
let thing:Thing = JSON.parse(`{"type": "NEW"}`);
alert(thing.type === Type.NEW); // true
这个可以工作,但需要很多样板代码,足以让我大部分时间不使用它。目前我希望“字符串枚举”的提案最终能够进入路线图。
更新 TS 2.1
新的keyof
类型查找 允许从常量或命名空间的键生成字符串字面类型,这使得定义稍微少了一些冗余:
namespace Type {
export const OLD = "OLD";
export const NEW = "NEW";
}
type Type = keyof typeof Type;
interface Thing { type: Type }
const thing: Thing = JSON.parse('{"type": "NEW"}');
thing.type == Type.NEW // true
更新TS 2.4
TypeScript 2.4 增加了对字符串枚举的支持!上述示例变为:
enum Type {
OLD = "OLD",
NEW = "NEW"
}
interface Thing { type: Type }
const thing: Thing = JSON.parse('{"type": "NEW"}');
alert(thing.type == Type.NEW) // true
这看起来已经非常完美了,但还存在一些心痛:
- 你仍然需要写两次值,比如
OLD = "OLD"
,而且没有验证你是否有拼写错误,比如NEW = "MEW"
...我在真实代码中已经因此遭受过损失。 枚举类型检查存在一些奇怪的问题(可能是bug),它不仅仅是一个字符串文字类型的简写,这才是真正正确的方式。我遇到过一些问题:
enum Color { RED = "RED", BLUE = "BLUE", GREEN = "GREEN" } type ColorMap = { [P in Color]: number; } declare const color: Color; declare const map: ColorMap; map[color] // Error: Element implicitly has an 'any' type because type 'ColorMap' has no index signature. const red: Color = "RED"; // Type '"RED"' is not assignable to type 'Color'. const blue: Color = "BLUE" as "RED" | "BLUE" | "GREEN"; // Error: Type '"RED" | "BLUE" | "GREEN"' is not assignable to type 'Color'.
使用字符串文字类型代替
enum Color
的等效代码可以正常工作...
是的,我认为我对此有强迫症,我只想要完美的JS枚举。:)
any
即可让编译器生成反向映射。如果您可以将这些信息编辑到您的答案中,那将非常有帮助。 - altocumulus<any>"string value"
(consistent-type-assertions)时,您的linter可能会显示警告。"解决方法"就是简单地改为"string value" as any
。 - Kaitype: Type
会让新手感到困惑。同样的问题也出现在命名为Type
的enum
中。使用明显不相关的名称,比如 "foo" 和 "bar" 或者至少是 "MyEnum"。 - user358041