json - 来自 JSON 字符串的 typescript `enum`

有没有办法让 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 值指定为 strings,而不是数字。

我知道我可以使用 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

使用 string literal types是另一种选择(感谢@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

这可行,但需要大量样板文件,足以让我大部分时间都不使用它。现在我希望 proposal for string enums最终会制定路线图。


更新 TS 2.1

新的keyof type lookup允许从 const 或命名空间的键生成字符串文字类型,这使得定义的 little 减少了冗余:

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 added support for string enums !上面的例子变成:

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"...这已经在实际代码中咬住了我。
  • 枚举的类型检查方式有些奇怪(可能是错误?),它不仅仅是字符串文字类型的简写,这才是真正正确的。我遇到的一些问题:

    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 枚举。 :)

最佳答案

如果您在 2.4 版本之前使用 Typescript,有一种方法可以通过将枚举的值转换为 any 来使用枚举来实现。

安example of your first implementation

enum Type {
    NEW = <any>"NEW",
    OLD = <any>"OLD",
}

interface Thing { type: Type }

let thing:Thing = JSON.parse('{"type": "NEW"}');

alert(thing.type == Type.NEW); // true

Typescript 2.4 has built in support for string enums已经,因此不再需要转换为 any 并且您可以在不使用 String Literal Union Type 的情况下实现它,这对于验证和自动完成来说是可以的,但对于可读性和重构来说不是那么好,具体取决于使用场景。

关于json - 来自 JSON 字符串的 typescript `enum`,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35760096/

相关文章:

ajax - 何时将 Ajax 与 Json 用于 Javascript 事件?

javascript - JSON 无法解析的垃圾 : Why so serious?

json - golang json编码(marshal): how to omit empty n

python - IPython Notebook 中漂亮的 JSON 格式

java - 如何测试 JSONObject 是否为空或不存在

python - json.loads 可以忽略尾随逗号吗?

ruby-on-rails - JBuilder中未定义的局部变量或方法 `json'

javascript - 如何从对象中删除所有 null 和空字符串值?

json - 有什么方法可以在运行时使用 webpack 加载资源?

javascript - 从 JSON 中选择不同的值