715 Stimmen

Wie konvertiere ich einen String in ein Enum in TypeScript?

Ich habe das folgende Enum in TypeScript definiert:

enum Color{
    Rot, Grün
}

Jetzt erhalte ich in meiner Funktion die Farbe als Zeichenkette. Ich habe den folgenden Code versucht:

var grün = "Grün";
var farbe : Color = grün; // Fehler: kann Zeichenkette nicht in Enum konvertieren

Wie kann ich diesen Wert in ein Enum konvertieren?

18voto

Chris Punkte 183

Ich bin auch auf den gleichen Compilerfehler gestoßen. Nur eine leicht verkürzte Variante von Sly_Cardinals Ansatz.

var color: Farbe = Farbe[colorId];

15voto

sgy Punkte 2622

Ich habe nach einer Antwort gesucht, die ein enum aus einem string erhalten kann, aber in meinem Fall hatten die Enum-Werte unterschiedliche String-Werte als Gegenstück. Der OP hatte ein einfaches Enum für Color, aber ich hatte etwas anderes:

enum Gender {
  Male = 'Male',
  Female = 'Female',
  Other = 'Other',
  CantTell = "Can't tell"
}

Wenn man versucht, Gender.CantTell mit einem "Can't tell" String aufzulösen, gibt das mit der originalen Antwort undefined zurück.

Eine andere Antwort

Grundsätzlich habe ich eine andere Antwort herausgebracht, die stark von dieser Antwort inspiriert war:

export const stringToEnumValue = (enumObj: ET, str: string): T =>
  (enumObj as any)[Object.keys(enumObj).filter(k => (enumObj as any)[k] === str)[0]];

Notizen

  • Wir nehmen das erste Ergebnis des filter, unter der Annahme, dass der Client einen gültigen String aus dem Enum übergibt. Wenn das nicht der Fall ist, wird undefined zurückgegeben.
  • Wir casten enumObj zu any, denn ab TypeScript 3.0+ (aktuell mit TypeScript 3.5) wird enumObj als unknown aufgelöst.

Beispiel zur Verwendung

const cantTellStr = "Can't tell";

const cantTellEnumValue = stringToEnumValue(Gender, cantTellStr);
console.log(cantTellEnumValue); // Can't tell

Hinweis: Und, wie jemand in einem Kommentar erwähnte, wollte ich auch das noImplicitAny verwenden.

Aktualisierte Version

Kein Casting zu any mehr und richtige Typisierung.

export const stringToEnumValue = (enumObj: T, value: string): T[keyof T] | undefined =>
  enumObj[Object.keys(enumObj).filter((k) => enumObj[k as K].toString() === value)[0] as keyof typeof enumObj];

Außerdem hat die aktualisierte Version eine einfachere Möglichkeit, sie aufzurufen und ist besser lesbar:

stringToEnumValue(Gender, "Can't tell");

10voto

mikeb Punkte 9727

Ich musste wissen, wie man über Enum-Werte iteriert (ich habe viele Permutationen mehrerer Enums getestet) und fand dies gut funktionieren:

export enum Environment {
    Prod = "http://asdf.com",
    Stage = "http://asdf1234.com",
    Test = "http://asdfasdf.example.com"
}

Object.keys(Environment).forEach((environmentKeyValue) => {
    const env = Environment[environmentKeyValue as keyof typeof Environment]
    // env ist jetzt gleichwertig mit Environment.Prod, Environment.Stage oder Environment.Test
}

Quelle: https://blog.mikeski.net/development/javascript/typescript-enums-to-from-string/

9voto

Flavien Volken Punkte 15992

TL;DR: Entweder:

  • Erstellen Sie eine Funktion, die den Stringwert analysiert und in ein Enum konvertiert.
  • Wenn Sie den Schlüsselnamen basierend auf dem Wert benötigen, verwenden Sie kein TS-Enum.

Zuerst einmal ist ein Enum eine Zuordnung zwischen einem menschenlesbaren Namen und einem Wert, dafür ist es gemacht.

Standardwerte: TS stellt standardmäßig sicher, dass Sie für die definierten Schlüssel des Enums einen eindeutigen Wert haben.

Dies

enum Color {
    Rot, Grün
}

ist äquivalent zu

enum Color {
    Rot = 0,
    Grün = 1
}

Der transpilierte JS-Code beider wird sein

"use strict";
var Color;
(function (Color) {
    Color[Color["Rot"] = 0] = "Rot";
    Color[Color["Grün"] = 1] = "Grün";
})(Color || (Color = {}));

Da dies unlesbar ist, hier ist das resultierende Objekt, sobald erstellt:

{0: 'Rot', 1: 'Grün', Rot: 0, Grün: 1}

Dieses Objekt hat String- und Nummereigenschaften (es kann keine Kollision geben, da Sie keinen Enum-Schlüssel als Zahl definieren können). TS ist cool genug, um ein Objekt zu generieren, das sowohl die Zuordnung Schlüssel -> Wert als auch Wert -> Schlüssel enthält.

Danke Gott, dies ist eine bijektive Zuordnung, d.h. ein jeder einzigartige Wert hat seinen einzigartigen Schlüssel (und umgekehrt gilt dies auch)

Jetzt kommen die Probleme, was ist, wenn ich den gleichen Wert erzwingen würde?

enum Color {
    Rot = 0,
    Grün = 0
}

Dies ist das resultierende erstellte JS-Objekt

{0: 'Grün', Rot: 0, Grün: 0}

Wir haben die Bijektivität nicht mehr (das ist surjektiv), es gibt keine magische Zuordnung 0 : ['Grün', 'Rot']. Nur 0 : 'Grün' und wir haben das 0 : 'Rot' verloren

Fazit: TS wird immer versuchen, die umgekehrte Zuordnung (Wert -> Schlüssel) zu setzen, wenn die Werte Zahlen sind.

Wie Sie vielleicht wissen, können Sie auch Zeichenfolgenwerte innerhalb eines Enums definieren, lassen Sie uns nur den Wert Grün auf "Green" ändern

enum Color {
    Rot = 0,
    Grün = "GRÜN"
}

Hier ist das resultierende JS-Objekt

{0: 'Rot', Rot: 0, Grün: 'GRÜN'}

Wie Sie sehen können, generiert Typescript nicht die Zuordnung Wert -> Schlüssel. Und es wird es nicht tun, weil es zu einer Kollision zwischen einem Wert und einem Schlüsselnamen kommen könnte. Denken Sie daran: ein Schlüssel kann keine Zahl sein, daher besteht kein Kollisionsrisiko, wenn der Wert eine Zahl ist.

Dies lässt Sie verstehen, dass Sie sich nicht auf die Zuordnung Wert -> Schlüssel eines Enums verlassen sollten. Die Zuordnung könnte einfach nicht existieren oder ungenau sein.

Wieder einmal sollte ein Enum als menschenlesbarer Name für einen Wert betrachtet werden. In einigen Fällen wird TS überhaupt keine umgekehrte Zuordnung generieren. Dies ist der Fall, wenn Sie ein Enum const definieren.

Ein const-Enum ist ein reines Kompilierzeit-Enum. TS wird die Verwendung des Enums durch seinen entsprechenden Wert bei der Transpilierung ersetzen

Zum Beispiel:

const enum Color {
    Rot = 0,
    Grün = "GRÜN"
}

wird transpiliert zu

"use strict";

Also um es kurz zu machen… nichts, weil "use strict"; nicht einmal mit dem übereinstimmt, was wir geschrieben haben.

Hier ist dasselbe Beispiel mit einer Verwendung:

const enum Color {
    Rot = 0,
    Grün = "GRÜN"
}
console.log(Color.Grün);

wird transpiliert zu

"use strict";
console.log("GRÜN" /* Green */);

Wie Sie sehen können, wird Color.Grün durch "GREEN" am Transpiler ersetzt.

Zurück zur ursprünglichen Frage, wie konvertieren Sie also eine Zeichenfolge in ein Enum?

Parser-Lösung: Es tut mir leid, aber die einzige saubere Methode, die ich empfehle, ist das Schreiben einer Funktion; die Verwendung eines switch case ist eine kluge Methode, um dies zu erreichen.

Funktion parseColorName(color: string): Color {
  switch (color) {
    case 'Rot': return Color.Rot;
    case 'Grün': return Color.Grün;
    default: throw new Error('Unbekannte Farbe');
  }
}

Benutzerdefinierte Enum-Lösung:

Beachten Sie, dass TS-Enums undurchsichtig sind, was bedeutet, dass es keine Möglichkeit für den Compiler gibt, den Wert ordnungsgemäß zu typisieren. Aus diesem Grund (und insbesondere wenn Sie die Rückwärtszuordnung verwenden müssen) würde ich empfehlen, Ihr eigenes Enum wie folgt zu erstellen:

export const Farbtyp = {
  ROT: 'Rot',
  GRÜN: 'Grün',
} as const;

export type Farbtyp = typeof Farbtyp[keyof typeof Farbtyp];

Das Folgende ist sicher (color kann nur einen gültigen bekannten Wert annehmen). Kurz gesagt, Sie verlassen sich auf Zeichenfolgenunionen anstelle eines Enum-Werts.

const farbe: Farbtyp = "Grün";
// Und wenn Sie eine Farbe aus dem Enumwert erstellen müssen:
const eineAndereFarbe: Farbtyp = Farbtyp.ROT;

8voto

Nick Punkte 9614

In dieser Frage gibt es viele gemischte Informationen, daher decken wir die gesamte Implementierung für TypeScript 2.x+ in Nicks Anleitung zur Verwendung von Enums in Modellen mit TypeScript ab.

Diese Anleitung richtet sich an: Personen, die clientseitigen Code erstellen, der eine Menge bekannter Zeichenfolgen vom Server aufnimmt, die auf der Clientseite bequem als Enum modelliert werden könnten.

Definiere das Enum

Lassen Sie uns mit dem Enum beginnen. Es sollte ungefähr so aussehen:

export enum IssueType {
  REPS = 'REPS',
  FETCH = 'FETCH',
  ACTION = 'ACTION',
  UNKNOWN = 'UNKNOWN',
}

Zwei Dinge sind hier zu beachten:

  1. Wir erklären diese explizit als Enum-Fälle mit Strings als Basis, was es uns ermöglicht, sie mit Strings zu instanziieren und nicht mit einigen anderen nicht verwandten Zahlen.

  2. Wir haben eine Option hinzugefügt, die möglicherweise nicht auf unserem Servermodell vorhanden ist: UNKNOWN. Dies kann als undefined behandelt werden, wenn Sie möchten, aber ich ziehe es vor, | undefined bei Typen möglichst zu vermeiden, um die Handhabung zu vereinfachen.

Das Tolle daran, einen UNKNOWN-Fall zu haben, ist, dass Sie im Code wirklich offensichtlich sein können und Stile für unbekannte Enum-Fälle hellrot und blinkend machen können, damit Sie wissen, dass Sie etwas nicht korrekt behandeln.

Enum analysieren

Sie verwenden dieses Enum möglicherweise eingebettet in einem anderen Modell oder ganz allein, aber Sie müssen das stringsgetypte Enum aus JSON oder XML (ha) in den stark typisierten Gegenpart umwandeln. Wenn es in einem anderen Modell eingebettet ist, befindet sich dieser Parser im Klassenkonstruktor.

parseIssueType(typeString: string): IssueType {
  const type = IssueType[typeString];
  if (type === undefined) {
    return IssueType.UNKNOWN;
  }

  return type;
}

Wenn das Enum ordnungsgemäß analysiert wird, landet es als der richtige Typ. Andernfalls wird es undefined sein und Sie können es abfangen und Ihren UNKNOWN-Fall zurückgeben. Wenn Sie undefined lieber als Ihren unbekannten Fall verwenden, können Sie einfach jedes Ergebnis aus dem Versuch des Enum-Analysierens zurückgeben.

Von da an geht es nur darum, die Parse-Funktion zu verwenden und Ihre neu stark typisierte Variable zu verwenden.

const strongIssueType: IssueType = parseIssueType('ACTION');
// IssueType.ACTION
const wrongIssueType: IssueType = parseIssueType('UNEXPECTED');
// IssueType.UNKNOWN

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X