一尘不染

JSON字符串的Typescript`enum`

json

有什么方法可以让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

这行得通,但要花很多时间,足以让我大部分时间不使用它。目前,我希望这项提案string enums最终能制定出路线图。


更新TS 2.1

新的keyof类型查找允许从const或名称空间的键生成字符串文字类型,这使定义 少了 一些冗余:

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


阅读 286

收藏
2020-07-27

共1个答案

一尘不染

如果您在2.4版本之前使用Typescript,则可以通过将枚举值转换为来使用枚举来实现any

首次实施示例

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已经内置了对字符串枚举的支持
,因此,any不再需要强制转换为,而无需使用,就可以实现它String Literal Union Type,这对于验证和自动完成是可以的,但对于可读性和重构则不太好,具体取决于使用场景。

2020-07-27