Typescript `enum` from JSON string

Gibt es eine Möglichkeit, eine TypeScript-Enumeration zu erstellen, die mit Strings von JSON kompatibel ist?

Beispielsweise

enum Type { NEW, OLD }

interface Thing { type: Type }

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

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

Ich würdemöge thing.type == Type.NEW um wahr zu sein. Oder genauer gesagt, ich wünschte, ich könnte das @ angebenum Werte, die als @ definiert werden soll strings, keine Zahlen.

Ich bin mir bewusst, dass ich @ verwenden kathing.type.toString() == Type[Type.NEW] aber das ist umständlich und scheint die Annotation des Aufzählungstyps verwirrend und irreführend zu machen, was ihren Zweck zunichte macht. Der JSON ist technischnich Geben Sie einen gültigen Aufzählungswert an, sodass ich die Eigenschaft nicht in die Aufzählung eingeben sollte.

So was ich gerade mache, ist die Verwendung eines Stringtyps mit statischen Konstanten:

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

interface Thing { type: string }

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

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

Dies bringt mir die gewünschte Verwendung, aber die Typanmerkungstring ist viel zu breit und fehleranfällig.

Ich bin ein bisschen überrascht, dass eine Obermenge von JavaScript keine auf Zeichenfolgen basierenden Aufzählungen enthält. Vermisse ich etwas? Gibt es eine andere Möglichkeit, dies zu tun?

Update TS 1.8

Usingstring Literaltypen ist eine andere Alternative (danke @basaret), aber um die gewünschte enum-artige Verwendung (oben) zu erhalten, müssen Sie Ihre Werte definierenzweima: einmal in einem Zeichenfolgenliteral und einmal als Wert (Konstante oder 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

Das funktioniert, braucht aber viel Kochplatte, genug, dass ich es die meiste Zeit nicht benutze. Vorerst hoffe ich dasVorschlag fürstring enums wird irgendwann die Roadmap machen.

Update TS 2.1

Das neuekeyof type lookup ermöglicht das Generieren des Zeichenfolgenliteraltyps aus den Schlüsseln einer Konstante oder eines Namespaces, wodurch die Definition zu einem @ wirweni weniger 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 unterstützt jetzt auch String-Enums! Das obige Beispiel lautet:

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

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

Das sieht ausfas perfekt, aber es gibt immer noch ein bisschen Herzschmerz:

Duimmer noc muss den Wert zweimal schreiben, dhOLD = "OLD", und es gibt keine Bestätigung, dass Sie keinen Tippfehler haben, wieNEW = "MEW" ... das hat mich schon in echten Code gebissen.

Es gibt einige Merkwürdigkeiten (vielleicht Fehler?), Wie die Aufzählung typüberprüft wird, es ist nicht nur eine Abkürzung vom Typ String-Literal, was wirklich richtig wäre. Einige Probleme, auf die ich gestoßen bin:

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'.

Der entsprechende Code mitenum Color ersetzt durch String-Literal-Typen funktionieren einwandfrei ...

Yeah, ich glaube, ich habe eine Zwangsstörung, ich möchte nur meine perfekten JS-Enums. :)

Antworten auf die Frage(8)

Ihre Antwort auf die Frage