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. :)