有没有办法让文字枚举与JSON中的字符串兼容?

例如:

enum Type { NEW, OLD }

interface Thing { type: Type }

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

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

我希望这是真的.或者更具体地说,我希望我可以将enum个值指定为strings,而不是数字.

我知道我可以使用thing.type.toString() == Type[Type.NEW],但这很麻烦,而且似乎使枚举类型注释令人困惑和误导,这违背了它的目的.从技术上讲,JSON是not,提供一个有效的枚举值,所以我不应该向枚举键入属性.

So what I am currently doing instead is using a string type with static constants:

const Type = { NEW: "NEW", OLD: "OLD" }

interface Thing { type: string }

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

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

这就得到了我想要的用法,但是类型注释string太宽泛,而且容易出错.

I'm a bit surprised that a superset of JavaScript doesn't have string based enums. Am I missing something? Is there a different way this can be done?


Update TS 1.8

Using string literal types is another alternative (thanks @basaret), but to get the desired enum-like usage (above) it requires defining your values twice: once in a string literal type, and once as a value (constant or namespace):

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

This works but takes a lot of boilerplate, enough that I don't use it most of the time. For now I'm hoping the proposal for string enums will eventually make the roadmap.


Update TS 2.1

The new keyof type lookup allows for the string literal type to be generated from the keys of a const or namespace, which makes the definition a little less redundant:

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

Update TS 2.4

TypeScript 2.4 added support for string enums! The above example becomes:

enum Type {
    OLD = "OLD",
    NEW = "NEW"
}

interface Thing { type: Type }
const thing: Thing = JSON.parse('{"type": "NEW"}');
alert(thing.type == Type.NEW) // true

This looks nearly perfect, but there's still some heartache:

  • 你必须写两次值,即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枚举.:)

推荐答案

If you are using Typescript before the 2.4 release, there is a way to achieve that with enums by casting the values of your enum to any.

An 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 already, so the cast to any would be no longer necessary and you could achieve it without the use of String Literal Union Type, which is ok for validation and autocomplete, but not so good for readability and refactoring, depending on the usage scenario.

Json相关问答推荐

如何循环访问多个子数组并在单个JSON中检索数据点

如何在Vega中使标记的符号在鼠标指针悬停时可点击

Jolt变换将字段移动到数组的每个元素中

GO KaZaam转换返回意外结果

将JSON数组组织到菜单中

使用 jq,如何将两个属性构成键的对象数组转换为对象的索引对象?

如何通过 jolt 将一个对象中的键和值添加到数组中的每个对象中

如何从 json 中获取单个元素?

添加到数组时出错:找不到Add的重载和参数计数:1

如何使用 jackson 反序列化为 Kotlin 集合

应该使用什么标头将 GZIP 压缩 JSON 从 Android 客户端发送到服务器?

在 Apache Spark 中读取多行 JSON

将字符串映射到json对象的多种类型?

直接从 Java 中的模型类创建 JSON 对象

android - 在 adb logcat 输出中格式化 json 字符串

如何让 javascript 从 .json 文件中读取?

POST:在 url 本身中发送 post 请求

Python 到 JSON 序列化在十进制上失败

Laravel 5 控制器将 JSON 整数作为字符串发送

如何从 github API 解析链接头