Wie konvertiere ich eine Zeichenfolge in TypeScript in Enum?


312

Ich habe die folgende Aufzählung in TypeScript definiert:

enum Color{
    Red, Green
}

Jetzt erhalte ich in meiner Funktion Farbe als Zeichenfolge. Ich habe den folgenden Code ausprobiert:

var green= "Green";
var color : Color = <Color>green; // Error: can't convert string to enum

Wie kann ich diesen Wert in eine Aufzählung umwandeln?

Antworten:


431

Aufzählungen in TypeScript 0.9 basieren auf Zeichenfolgen und Zahlen. Für einfache Konvertierungen sollten Sie keine Typzusicherung benötigen:

enum Color{
    Red, Green
}

// To String
 var green: string = Color[Color.Green];

// To Enum / number
var color : Color = Color[green];

Probieren Sie es online aus

Ich habe eine Dokumentation zu diesem und anderen Enum-Mustern in meinem OSS-Buch: https://basarat.gitbook.io/typescript/type-system/enums


112
Dies funktioniert nicht mit --noImplicitAny(in VS deaktiviert "Implizite 'beliebige' Typen zulassen"). Es produziert error TS7017: Index signature of object type implicitly has an 'any' type.Für mich hat das funktioniert: var color: Color = (<any>Color)[green];(getestet mit Version 1.4)
Vojta

3
@ Vojta sagte richtig. Es funktioniert nicht in VS 2012. Dieses hat funktioniert, aber var color: Color = (<any> Color) [grün];
Faisal Mq

3
Auch hier funktioniert es nicht, die offizielle Dokumentation scheint dies zu bestätigen: typescriptlang.org/docs/handbook/release-notes/…
Pieter De Bie

26
Stellen Sie sicher, dass Sie dies verwenden, wenn --noImplicitAnyvar color : Color = Color[green as keyof typeof Color];
Jonas

2
@ Naxos84 Siehe meine answear stackoverflow.com/a/56076148/294242
Jonas

123

Ab Typescript 2.1 sind Zeichenfolgenschlüssel in Aufzählungen stark typisiert. keyof typeofwird verwendet, um Informationen zu verfügbaren Zeichenfolgenschlüsseln ( 1 ) abzurufen :

enum Color{
    Red, Green
}

let typedColor: Color = Color.Green;
let typedColorString: keyof typeof Color = "Green";

// Error "Black is not assignable ..." (indexing using Color["Black"] will return undefined runtime)
typedColorString = "Black";

// Error "Type 'string' is not assignable ..." (indexing works runtime)
let letColorString = "Red";
typedColorString = letColorString;

// Works fine
typedColorString = "Red";

// Works fine
const constColorString = "Red";
typedColorString = constColorString

// Works fine (thanks @SergeyT)
let letColorString = "Red";
typedColorString = letColorString as keyof typeof Color;

typedColor = Color[typedColorString];

https://www.typescriptlang.org/docs/handbook/advanced-types.html#index-types


4
So können wir let s = "Green"; let typedColor = <keyof typeof Color> s;
typecast

Ja, und das Ersetzen letdurch constfunktioniert ohne Gießen. Beispiel aktualisiert, um dies zu verdeutlichen. Danke @SergeyT
Victor

1
typedColorString = Color["Black"];kehrt jetzt zurückerror TS7015: Element implicitly has an 'any' type because index expression is not of type 'number'
Dominik

2
Eine einzeilige Antwort:const color: Color = Color[colorString as keyof typeof Color];
cscan

38

Wenn Sie sicher sind, dass eine Eingabezeichenfolge genau mit der Farbaufzählung übereinstimmt, verwenden Sie:

const color: Color = (<any>Color)["Red"];

Verwenden Sie Folgendes, wenn eine Eingabezeichenfolge möglicherweise nicht mit Enum übereinstimmt:

const mayBeColor: Color | undefined = (<any>Color)["WrongInput"];
if (mayBeColor !== undefined){
     // TypeScript will understand that mayBeColor is of type Color here
}

Spielplatz


Wenn wir nicht enumin <any>Typ umwandeln, zeigt TypeScript den Fehler an:

Das Element hat implizit den Typ 'any', da der Indexausdruck nicht vom Typ 'number' ist.

Dies bedeutet, dass der TypeScript-Aufzählungstyp standardmäßig mit Zahlenindizes funktioniert, dh let c = Color[0]nicht mit Zeichenfolgenindizes wie let c = Color["string"]. Dies ist eine bekannte Einschränkung des Microsoft-Teams für das allgemeinere Problem Objektzeichenfolgenindizes .


Sie können auch auf <keyof typeof Color> umwandeln. Auch "0" ist ebenfalls eine falsche Eingabe, gibt aber nicht undefiniert zurück. Überprüfen Sie daher den Typ von mayBeColor === 'number'
Quentin 2

@ Quentin2 was ist mit einer numerischen Zeichenfolge? dh typeof '0'sollte seinstring
Patrick Michaelsen

36
enum Color{
    Red, Green
}

// To String
 var green: string = Color[Color.Green];

// To Enum / number
var color : Color = Color[green as keyof typeof Color]; //Works with --noImplicitAny

Dieses Beispiel funktioniert --noImplicitAnyin TypeScript

Quellen:
https://github.com/Microsoft/TypeScript/issues/13775#issuecomment-276381229 https://www.typescriptlang.org/docs/handbook/advanced-types.html#index-types


Ich weiß nicht , warum, aber diese Lösung funktioniert nicht auf auf einem const Enum (mit Typoskript 3.8.3)
Robin-Hoodie

30

Dieser Hinweis bezieht sich auf die Antwort von Basarat , nicht auf die ursprüngliche Frage.

Ich hatte ein seltsames Problem in meinem eigenen Projekt, bei dem der Compiler einen Fehler gab, der ungefähr "Zeichenfolge kann nicht in Farbe konvertieren" entspricht, indem er das Äquivalent dieses Codes verwendet:

var colorId = myOtherObject.colorId; // value "Green";
var color: Color = <Color>Color[colorId]; // TSC error here: Cannot convert string to Color.

Ich stellte fest, dass die Inferenz des Compilertyps verwirrt war und dachte, dies colorIdsei ein Aufzählungswert und keine ID. Um das Problem zu beheben, musste ich die ID als Zeichenfolge umwandeln:

var colorId = <string>myOtherObject.colorId; // Force string value here
var color: Color = Color[colorId]; // Fixes lookup here.

Ich bin nicht sicher, was das Problem verursacht hat, aber ich werde diese Notiz hier hinterlassen, falls jemand auf dasselbe Problem stößt, das ich getan habe.


Danke dir! Dies ist ein ziemlich dummes Problem und schwer herauszufinden, wo das Problem liegt. Möglicherweise sollte Typescript in Betracht ziehen, eine bessere Methode für den Umgang mit Aufzählungen zu finden.
ChickenFeet

25

Ich habe es mit dem folgenden Code zum Laufen gebracht.

var green= "Green";
var color : Color= <Color>Color[green];

23

Wenn Sie Ihrer Aufzählung Zeichenfolgenwerte bereitstellen, funktioniert eine gerade Umwandlung einwandfrei.

enum Color {
  Green = "Green",
  Red = "Red"
}

const color = "Green";
const colorEnum = color as Color;

1
Sehr einfach. Nett!
Bernoulli IT

1
Dies kann irreführend sein, da es nicht vor ungültigen Farben schützt. const colorEnum = "Blue" as Colorwird keinen Fehler machen, und Sie würden denken, dass colorEnumdas in Ordnung ist. Aber wenn Sie dabei wären console.log, würden Sie "Blau" sehen. Artrus Antwort ist nett, weil colorEnumes so sein wird undefined- und Sie können das dann genau überprüfen.
M Falanga

20

Vorausgesetzt, Sie verwenden Typoskript: Viele der oben genannten Lösungen funktionieren möglicherweise nicht oder sind zu komplex.

Situation : Die Zeichenfolgen stimmen nicht mit den Enum-Werten überein (Gehäuse unterscheidet sich)

enum Color {
  Green = "green",
  Red = "red"
}

Benutz einfach:

const color = "green" as Color

15

Ich bin auch auf den gleichen Compilerfehler gestoßen. Nur eine etwas kürzere Variante des Ansatzes von Sly_cardinal.

var color: Color = Color[<string>colorId];

Als Ergänzung: Wenn Sie eine Typoskript-Aufzählung haben, die von einer Javascript-Ebene gefüllt ist, die die Aufzählung als Zeichenfolge serialisiert (z. B. Asp Web API über AngularJS), können Sie myProp.color = Color[<string><any>myProp.color] Cheers
Victor

1
Dies muss die anerkannte Antwort sein.
Miroslav Popov

9

Wenn der TypeScript-Compiler weiß, dass der Variablentyp Zeichenfolge ist, funktioniert dies:

let colorName : string = "Green";
let color : Color = Color[colorName];

Andernfalls sollten Sie es explizit in eine Zeichenfolge konvertieren (um Compiler-Warnungen zu vermeiden):

let colorName : any = "Green";
let color : Color = Color["" + colorName];

Zur Laufzeit funktionieren beide Lösungen.


3
Warum nicht einfach Typecast <string>colorNameanstelle von verwenden "" + colorName?
SergeyT

7

Diese Frage enthält viele gemischte Informationen. Lassen Sie uns daher die gesamte Implementierung von TypeScript 2.x + in Nicks Handbuch zur Verwendung von Enums in Modellen mit TypeScript behandeln .

Dieses Handbuch richtet sich an Personen, die clientseitigen Code erstellen, der eine Reihe bekannter Zeichenfolgen vom Server aufnimmt, die auf der Clientseite bequem als Enum modelliert werden.

Definieren Sie die Aufzählung

Beginnen wir mit der Aufzählung. Es sollte ungefähr so ​​aussehen:

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

Zwei Dinge, die hier zu beachten sind:

  1. Wir deklarieren diese explizit als Zeichenfolgen-Backed-Enum-Fälle, die es uns ermöglichen, sie mit Zeichenfolgen zu instanziieren, nicht mit anderen nicht verwandten Zahlen.

  2. Wir haben eine Option hinzugefügt, die in unserem Servermodell möglicherweise vorhanden ist oder nicht : UNKNOWN. Dies kann so gehandhabt werden, wie undefinedSie es bevorzugen, aber ich vermeide es | undefined, wenn möglich, Typen zu verwenden, um die Handhabung zu vereinfachen.

Das Tolle an einem UNKNOWNFall ist, dass Sie im Code wirklich offensichtlich sein und Stile für unbekannte Enum-Fälle hellrot und blinkend erstellen können, damit Sie wissen, dass Sie mit etwas nicht richtig umgehen.

Analysieren Sie die Aufzählung

Möglicherweise verwenden Sie diese Aufzählung, die in ein anderes Modell eingebettet ist, oder ganz alleine, aber Sie müssen die Aufzählung mit String-y-Typ aus JSON oder XML (ha) in Ihr stark typisiertes Gegenstück analysieren. Wenn dieser Parser in ein anderes Modell eingebettet ist, befindet er sich im Klassenkonstruktor.

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

  return type;
}

Wenn die Aufzählung richtig analysiert wird, wird sie als der richtige Typ angezeigt. Andernfalls wird es sein undefinedund Sie können es abfangen und Ihren UNKNOWNFall zurückgeben. Wenn Sie es vorziehen, undefinedals unbekannten Fall zu verwenden, können Sie einfach jedes Ergebnis der versuchten Enum-Analyse zurückgeben.

Von dort aus müssen Sie nur noch die Analysefunktion und Ihre neu stark typisierte Variable verwenden.

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

6
Leider scheint dies nicht korrekt oder zumindest nicht verallgemeinerbar zu sein. Es funktioniert, weil Ihre Schlüssel den Zeichenfolgen entsprechen, die ihnen zugewiesen wurden. Wenn sie sich jedoch wie in meinem Fall unterscheiden, funktioniert dies nicht. In den Worten der Dokumentation : "Beachten Sie, dass Mitglieder der String-Aufzählung überhaupt keine umgekehrte Zuordnung erhalten." Ihr Code wird zu so etwas kompiliert IssueType["REPS"]="REPS". Wenn Sie Ihre Aufzählung ein wenig anders definiert REPS="reps"hätten , würde dies ergeben, IssueType["REPS"]="reps"was ...
Altocumulus

... kehren Sie immer zurück, IssueType.UNKNOWNweil repsIhre Aufzählung keinen Schlüssel enthält . Schade, ich habe immer noch keine funktionierende Lösung dafür gefunden, da meine Zeichenfolgen Bindestriche enthalten, die sie als Schlüssel unbrauchbar machen.
Altocumulus

Schließlich fand ich in dieser Antwort eine Lösung , indem ich den Compiler davon überzeugte, dass dies keine String-Aufzählung war. Es könnte sich lohnen, diese Informationen in Ihrer eigenen Antwort zu bearbeiten.
Altocumulus

7

Ich suchte nach einer Antwort, die eine enumvon a erhalten kann string, aber in meinem Fall hatten die Aufzählungswerte unterschiedliche Gegenstücke zu Zeichenfolgenwerten. Das OP hatte eine einfache Aufzählung für Color, aber ich hatte etwas anderes:

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

Wenn Sie versuchen, Gender.CantTellmit einer "Can't tell"Zeichenfolge aufzulösen , wird diese zurückgegebenundefined die ursprüngliche Antwort zurückgegeben.

Eine andere Antwort

Grundsätzlich habe ich eine andere Antwort gefunden, die stark von dieser Antwort inspiriert ist :

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

Anmerkungen

  • Wir nehmen das erste Ergebnis von an filter, vorausgesetzt, der Client übergibt eine gültige Zeichenfolge aus der Aufzählung. Wenn dies nicht der Fall ist,undefined wird zurückgegeben.
  • Wir werfen enumObjauf any, weil mit TypeScript 3.0+ (derzeit mit TypeScript 3.5) das enumObjals aufgelöst wird unknown.

Anwendungsbeispiel

const cantTellStr = "Can't tell";

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

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

Aktualisierte Version

Keine Besetzung anyund korrekte Eingabe.

export const stringToEnumValue = <T, K extends keyof T>(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];

Die aktualisierte Version lässt sich auch einfacher aufrufen und ist besser lesbar:

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

6

Ich musste wissen, wie man Enum-Werte durchläuft (testete viele Permutationen mehrerer Enums) und fand, dass dies gut funktioniert:

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 is now equivalent to Environment.Prod, Environment.Stage, or Environment.Test
}

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


Diese Antwort ist genial! Liebe es. Besonders die Art und Weise, wie Sie aus der Zeichenfolge eine Aufzählung machen. Dies kann Ihnen beim Testen von Aufzählungen oder anderen Fällen so viel Eingabe ersparen.
Florian Leitgeb

Ja, ich benutze dies mit Jest's each, um jeden einzelnen Enum-Fall mit nur einer Methode zu testen
Mikeb

3

Aufzählung

enum MyEnum {
    First,
    Second,
    Three
}

Beispielnutzung

const parsed = Parser.parseEnum('FiRsT', MyEnum);
// parsed = MyEnum.First 

const parsedInvalid= Parser.parseEnum('other', MyEnum);
// parsedInvalid = undefined

Groß- und Kleinschreibung ignorieren

class Parser {
    public static parseEnum<T>(value: string, enumType: T): T[keyof T] | undefined {
        if (!value) {
            return undefined;
        }

        for (const property in enumType) {
            const enumMember = enumType[property];
            if (typeof enumMember === 'string') {
                if (enumMember.toUpperCase() === value.toUpperCase()) {
                    const key = enumMember as string as keyof typeof enumType;
                    return enumType[key];
                }
            }
        }
        return undefined;
    }
}

Jeder, der eine Aufzählung wie ich hat, sollte return enumType[property];einen Fall Skills = "anyvalue"
einreichen

@ neustart47 könntest du bitte die frage stellen?
14р Дармаев

Das ist keine Frage. Ich habe gerade einige Änderungen für jeden erwähnt, der nach dem gleichen Fall sucht wie ich. Ihre Antwort ist richtig.
neustart47

2

Auf Ihre Weise erstellte Aufzählungen werden zu einem Objekt kompiliert, in dem sowohl Vorwärts- (name -> value)als auch Rückwärtszuordnungen (value -> name)gespeichert sind. Wie wir aus diesem Screenshot von Chrome Devtools ersehen können:

Geben Sie hier die Bildbeschreibung ein

Hier ist ein Beispiel dafür, wie Dual Mapping funktioniert und wie man von einem zum anderen wechselt:

enum Color{
    Red, Green
}
// To Number
var greenNr: number = Color['Green'];
console.log(greenNr); // logs 1

// To String
var greenString: string = Color[Color['Green']];  // or Color[Color[1]
console.log(greenString); // logs Green

// In your example

// recieve as Color.green instead of the string green
var green: string = Color[Color.Green];  

// obtain the enum number value which corresponds to the Color.green property
var color: Color = (<any>Color)[green];  

console.log(color); // logs 1

1

Versuche dies

var color: Color = (Farbe wie jede andere) ["Grün];

Das funktioniert gut für die Version 3.5.3


0

Wenn Sie Namespaces verwenden, um die Funktionalität Ihrer Aufzählung zu erweitern, können Sie auch so etwas tun

    enum Color {
        Red, Green
    }

    export namespace Color {
      export function getInstance(color: string) : Color {
        if(color == 'Red') {
          return Color.Red;
        } else if (color == 'Green') {
          return Color.Green;
        }
      }
    }

und benutze es so

  Color.getInstance('Red');

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.