当前位置: 首页 > 知识库问答 >
问题:

JSON字符串中的Typescript`enum`

慎弘化
2023-03-14

是否有任何方法使TypeScript枚举与JSON中的字符串兼容?

例如:

enum Type { NEW, OLD }

interface Thing { type: Type }

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

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

我想要东西。类型==类型。新的是真的。或者更具体地说,我希望可以将enum值指定为字符串,而不是数字。

我知道我可以使用东西。类型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

新的keyoftype lookup允许从常量或命名空间的键生成字符串文本类型,这使得定义的冗余度降低了一点:

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

  • 共有3个答案

    卫宏硕
    2023-03-14

    TS 2.9.2
    我的解决方案

    export enum Enums { VALUE1, VALUE2 }
    

    当我从API json中获得值时:

     switch (response.enumValue.toString()) { //can be without toString if we have string value from JSON.
        case Enums[Enums.VALUE1]:
          ...
        case Enums[Enums.VALUE2]:
          ...
     }
    
    桑璞
    2023-03-14

    如果2021年有人还在看这个问题:

    @亚伦在最初的问题中写道:

    这看起来近乎完美,但仍然有一些心痛:

    你仍然必须[…]

    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.
    // [...]
    

    将枚举颜色替换为字符串文字类型的等效代码运行良好。。。

    是的,我想我有强迫症,我只想要我完美的JS枚举。:)

    关于,

    将枚举颜色替换为字符串文字类型的等效代码运行良好。。。

    使用typeofkeyof操作符进行链式连接。

    type ColorKeys = keyof typeof Color
    type ColorMap = { [P in ColorKeys]: number; } // will have strongly typed keys
    

    当访问map:ColorMap时,不再有任何隐式any
    这也适用于数字枚举(可以(而且通常应该)是const)。

    摘自Typecript Handbook-编译时的Enus:

    尽管枚举是在运行时存在的真实对象,但keyof关键字的工作方式可能与典型对象的工作方式不同。相反,使用keyof typeof获取一个将所有枚举键表示为字符串的类型。

    查看ts enum util,它为(可能)所有与enum相关的需求提供强类型接口。

    冯星阑
    2023-03-14

    如果在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已经内置了对字符串枚举的支持,因此不再需要强制转换为任何,您可以在不使用String Litald Union Type的情况下实现它,这对于验证和自动完成是可以的,但对于易读性和重构不是很好,这取决于使用场景。

     类似资料:
    • 问题内容: 有什么方法可以让TypeScript枚举与JSON中的字符串兼容? 例如: 我 想 是真的。更具体地说,我希望可以将值定义为 字符串 ,而不是数字。 我知道我可以使用,但这很麻烦,而且似乎使枚举类型注释变得混乱和误导,从而违背了它的目的。JSON从技术上讲 不会 提供有效的枚举值,因此我不应该在枚举中键入属性。 所以我目前正在做的是使用带有静态常量的字符串类型: 这为我提供了我想要的用

    • 问题内容: 有没有一种方法可以将Typescript中的字符串解析为JSON。 示例:在JS中,我们可以使用。Typescript中有类似的功能吗? 我有一个JSON对象字符串,如下所示: 问题答案: Typescript是javascript(的超集),因此您可以像在javascript中那样使用它: 只有在打字稿中,您才能对结果对象进行打字: (操场上的代码)

    • 在typescript中有没有一种方法可以将字符串解析为JSON。 示例:在JS中,我们可以使用。在Typescript中有类似的功能吗? 我有一个JSON对象字符串,如下所示:

    • 因此,进一步寻找,我发现这个人有一个解决方案:typescript中基于字符串的枚举的解决方案 这将允许像这样的东西工作: 唯一的回应基本上是说这样做是不安全的。(但我应该说,它确实起作用了--我可以键入eventtype.dot...Atom editor给了我5个大小写选项可供选择(保持代码中的内容一致),然后我可以使用它将字符串值吐出来,给我的用户一个很好的填充空间的体验,将来我可以更改枚举

    • 问题内容: 我正在寻找一种在字符串中查找JSON数据的方法。像wordpress简码一样思考它。我认为最好的方法是使用正则表达式。我不想解析JSON,只需查找所有出现的事件。 正则表达式中是否有办法使括号的数量匹配?目前,当我嵌套对象时遇到了这个问题。 演示的快速示例: 结果,我想要两个JSON字符串。谢谢! 问题答案: 从给定的文本中提取JSON字符串 由于您正在寻找一种简单的解决方案,因此可以

    • 我正在与返回JSON的Axios进行API调用。API将CUSIP返回为类型String,但是,我希望将其接收为类型Number。我创建了一个接口,它具有类型类型为数字,但是当我得到变量时,它仍然被视为字符串。 API调用和一些逻辑: 名为General的接口,其中我将CUSIP转换为数字: 问题是:不是将[CUSIP 1337]打印为[2 1337=1339],而是打印[21337]。我很乐意帮