来自 JSON 字符串的打字稿“enum”

2024-01-02

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

例如:

enum Type { NEW, OLD }

interface Thing { type: Type }

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

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

I would like thing.type == Type.NEW是真实的。或者更具体地说,我希望我可以指定enum值定义为strings,不是数字。

我知道我可以使用thing.type.toString() == Type[Type.NEW]但这很麻烦,并且似乎使枚举类型注释变得混乱和误导,这违背了它的目的。 JSON 从技术上讲是not提供有效的枚举值,因此我不应该将属性键入到枚举中。

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

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

Using 字符串文字类型 https://github.com/Microsoft/TypeScript/wiki/What's-new-in-TypeScript#string-literal-types是另一种选择(感谢@basaret),但是为了获得所需的类似枚举的用法(上面),它需要定义您的值twice:一次是字符串文字类型,一次是作为值(常量或命名空间):

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 https://github.com/Microsoft/TypeScript/issues/1206#issuecomment-240581743最终将制定路线图。


更新TS 2.1

The new keyof类型查找 https://github.com/Microsoft/TypeScript/wiki/What's-new-in-TypeScript#keyof-and-lookup-types允许从 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 添加了对字符串枚举的支持 https://github.com/Microsoft/TypeScript/wiki/What's-new-in-TypeScript#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

这看起来nearly完美,但还是有一些心痛:

  • You still必须将该值写入两次,即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.

An 您的第一个实现的示例 https://www.typescriptlang.org/play/index.html#src=enum%20Type%20%7B%0D%0A%20%20%20%20NEW%20%3D%20%22NEW%22%2C%0D%0A%20%20%20%20OLD%20%3D%20%22OLD%22%2C%0D%0A%7D%0D%0A%0D%0Ainterface%20Thing%20%7B%20type%3A%20Type%20%7D%0D%0A%0D%0Alet%20thing%3AThing%20%3D%20JSON.parse('%7B%22type%22%3A%20%22NEW%22%7D')%3B%0D%0A%0D%0Aalert(thing.type%20%3D%3D%20Type.NEW)%3B%20%2F%2F%20true#src=enum%20Type%20%7B%0D%0A%20%20%20%20NEW%20%3D%20%3Cany%3E%22NEW%22%2C%0D%0A%20%20%20%20OLD%20%3D%20%3Cany%3E%22OLD%22%2C%0D%0A%7D%0D%0A%0D%0Ainterface%20Thing%20%7B%20type%3A%20Type%20%7D%0D%0A%0D%0Alet%20thing%3AThing%20%3D%20JSON.parse('%7B%22type%22%3A%20%22NEW%22%7D')%3B%0D%0A%0D%0Aalert(thing.type%20%3D%3D%20Type.NEW)%3B%20%2F%2F%20true

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 内置了对字符串枚举的支持 https://blogs.msdn.microsoft.com/typescript/2017/06/27/announcing-typescript-2-4/已经,所以演员any将不再需要,您无需使用即可实现它String Literal Union Type https://www.typescriptlang.org/docs/handbook/advanced-types.html#string-literal-types,这对于验证和自动完成来说还可以,但对于可读性和重构来说不太好,具体取决于使用场景。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

来自 JSON 字符串的打字稿“enum” 的相关文章

随机推荐