来自 JSON 字符串的打字稿`enum` [英] Typescript `enum` from JSON string

查看:18
本文介绍了来自 JSON 字符串的打字稿`enum`的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

有没有办法让 TypeScript 枚举与来自 JSON 的字符串兼容?

Is there any way to have a TypeScript enum compatible with strings from 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,而不是数字.

I would like thing.type == Type.NEW to be true. Or more specifically, I wish I could specify the enum values to be defined as strings, not numbers.

我知道我可以使用 thing.type.toString() == Type[Type.NEW] 但这很麻烦并且似乎使枚举类型注释混乱和误导,这使它的目的.JSON 在技术上提供有效的枚举值,所以我不应该将属性输入到枚举中.

I am aware that I can use thing.type.toString() == Type[Type.NEW] but this is cumbersome and seems to make the enum type annotation confusing and misleading, which defeats its purpose. The JSON is technically not supplying a valid enum value, so I shouldn't type the property to the enum.

所以我目前正在做的是使用带有静态常量的字符串类型:

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 太宽泛且容易出错.

This gets me the usage I want, but the type annotation string is way too broad and error prone.

我有点惊讶 JavaScript 的超集没有基于字符串的枚举.我错过了什么吗?有没有不同的方法可以做到这一点?

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?

更新 TS 1.8

使用字符串文字类型是另一种选择(感谢@basaret),但要获得所需的类似枚举的用法(以上),它需要定义您的值两次:一次在字符串文字类型中,一次作为值(常量或命名空间):

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.

更新 TS 2.1

新的keyof 类型查找 允许从常量或命名空间的键生成字符串文字类型,这使得定义little 不那么冗余:

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

<小时>

更新 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

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

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

  • 仍然必须将值写入两次,即 OLD = "OLD",并且没有验证您没有输入错误,例如 NEW = "MEW"...这已经在真正的代码中咬我了.
  • 枚举的类型检查方式有一些奇怪(也许是错误?),它不仅仅是字符串文字类型的速记,这才是真正正确的.我遇到的一些问题:

  • You still have to write the value twice, ie OLD = "OLD", and there's no validation that you don't have a typo, like NEW = "MEW"... this has already bitten me in real code.
  • There's some oddities (perhaps bugs?) with how the enum is type checked, its not just a string literal type shorthand, which is what would be truly correct. Some issues I've bumped into:

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 替换为字符串文字类型的等效代码工作正常...

The equivalent code with enum Color replaced by string literal types work fine...

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

Yeah, I think I have OCD about this, I just want my perfect JS enums. :)

推荐答案

如果您在 2.4 版本之前使用 Typescript,则可以通过将枚举的值强制转换为 any.

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.

您的第一个实现示例

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,这对于验证和自动完成是可以的,但对于可读性和重构,取决于使用场景.

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 字符串的打字稿`enum`的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆