Come faccio a convertire una stringa in enum in TypeScript?


312

Ho definito il seguente enum in TypeScript:

enum Color{
    Red, Green
}

Ora nella mia funzione ricevo il colore come una stringa. Ho provato il seguente codice:

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

Come posso convertire quel valore in un enum?

Risposte:


431

Gli enumeratori in TypeScript 0.9 sono basati su string + number. Non dovresti aver bisogno di un'asserzione di tipo per conversioni semplici:

enum Color{
    Red, Green
}

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

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

Provalo online

Ho una documentazione su questo e altri schemi Enum nel mio libro OSS: https://basarat.gitbook.io/typescript/type-system/enums


112
Questo non funziona con --noImplicitAny(in VS deselezionato "Consenti 'qualsiasi' tipo implicito"). Produce error TS7017: Index signature of object type implicitly has an 'any' type.per me questo ha funzionato: var color: Color = (<any>Color)[green];(testato con la versione 1.4)
Vojta

3
@Vojta ha detto bene. Non funziona in VS 2012. Questo ha funzionato ma var color: Color = (<any> Color) [verde];
Faisal Mq

3
Non funziona neanche qui, la documentazione ufficiale sembra confermare che: typescriptlang.org/docs/handbook/release-notes/…
Pieter De Bie

26
Assicurati di usare questo se --noImplicitAny var color : Color = Color[green as keyof typeof Color];
Jonas

2
@ Naxos84 vedere la mia answear stackoverflow.com/a/56076148/294242
Jonas

123

A partire da Typescript le chiavi di stringa 2.1 in enum sono fortemente tipizzate. keyof typeofviene utilizzato per ottenere informazioni sulle chiavi di stringa disponibili ( 1 ):

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
Quindi possiamo usare il typecast:let s = "Green"; let typedColor = <keyof typeof Color> s;
SergeyT

Sì, e la sostituzione letcon constfunzionerà senza lanciare. Esempio aggiornato per chiarire questo. Grazie @SergeyT
Victor,

1
typedColorString = Color["Black"];ora ritornaerror TS7015: Element implicitly has an 'any' type because index expression is not of type 'number'
Dominik,

2
Una risposta di una riga:const color: Color = Color[colorString as keyof typeof Color];
cscan

38

Se sei sicuro che una stringa di input abbia una corrispondenza esatta con Enum Color, usa:

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

Nel caso in cui una stringa di input non corrisponda a Enum, utilizzare:

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

Terreno di gioco


Se non eseguiamo il cast enumper <any>digitare, TypeScript mostrerà l'errore:

L'elemento ha implicitamente "qualsiasi" tipo perché l'espressione dell'indice non è di tipo "numero".

Vuol dire che per impostazione predefinita il tipo Enum TypeScript funziona con indici numerici, ovvero let c = Color[0], ma non con indici stringa come let c = Color["string"]. Questa è una restrizione nota da parte del team di Microsoft per il problema più generale Indici di stringa di oggetti .


Puoi anche eseguire il cast su <keyof typeof Color>. Anche "0" è un input errato ma non restituirà un indefinito, quindi controlla typeof mayBeColor === 'number'
Quentin 2

@ Quentin2 che ne dici di una stringa numerica? cioè typeof '0'dovrebbe esserestring
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

Questo esempio funziona con --noImplicitAnyin TypeScript

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


Non so perché, ma questa soluzione non funziona su un const enum (usando Typescript 3.8.3)
Robin-Hoodie

30

Questa nota si riferisce alla risposta di Basarat , non alla domanda originale.

Ho avuto un problema strano nel mio progetto in cui il compilatore stava dando un errore approssimativamente equivalente a "impossibile convertire la stringa in colore" usando l'equivalente di questo codice:

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

Ho scoperto che l'inferenza del tipo di compilatore si stava confondendo e pensava che colorIdfosse un valore enum e non un ID. Per risolvere il problema ho dovuto trasmettere l'ID come stringa:

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

Non sono sicuro di cosa abbia causato il problema, ma lascio qui questa nota nel caso qualcuno incontrasse lo stesso problema che ho fatto.


Grazie! Questo è un problema piuttosto sciocco e difficile da capire quale sia il problema. Forse Typescript dovrebbe prendere in considerazione l'idea di trovare un modo migliore di gestire gli enum.
Pollo:

25

Ho funzionato usando il seguente codice.

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

23

Se fornisci valori di stringa al tuo enum, un cast dritto funziona bene.

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

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

1
Molto semplice. Bello!
Bernoulli IT

1
Questo potrebbe essere fuorviante in quanto non protegge da colori non validi. const colorEnum = "Blue" as Colornon sbaglierà e rimarrai pensando che colorEnumsia OK. Ma se ci fossi console.log, vedresti "Blu". La risposta di Artru è buona, perché colorEnumlo sarà undefined- e puoi verificarla in modo specifico.
M Falanga,

20

Dato che usi il dattiloscritto: molte delle soluzioni sopra potrebbero non funzionare o sono eccessivamente complesse.

Situazione : le stringhe non coincidono con i valori enum (il case differisce)

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

Usa solo:

const color = "green" as Color

15

Ho anche incontrato lo stesso errore del compilatore. Solo una leggera variazione più breve dell'approccio di Sly_cardinal.

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

Come aggiunta: nel caso in cui tu abbia un enum dattiloscritto riempito da un layer javascript che serializza l'enum come stringa (diciamo ad esempio Asp Web API tramite AngularJS) puoi fare myProp.color = Color[<string><any>myProp.color] Saluti
Victor

1
Questa deve essere la risposta riconosciuta.
Miroslav Popov,

9

Se il compilatore TypeScript sa che il tipo di variabile è stringa, allora funziona:

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

Altrimenti dovresti convertirlo esplicitamente in una stringa (per evitare gli avvisi del compilatore):

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

In fase di esecuzione entrambe le soluzioni funzioneranno.


3
perché non usare solo typecast <string>colorNameinvece di "" + colorName?
SergeyT

7

Ci sono molte informazioni contrastanti in questa domanda, quindi copriamo l'intera implementazione per TypeScript 2.x + nella Guida di Nick all'utilizzo degli enum nei modelli con TypeScript .

Questa guida è per: le persone che stanno creando codice sul lato client che sta ingerendo dal server un set di stringhe note che sarebbero opportunamente modellate come Enum sul lato client.

Definisci l'enum

Cominciamo con l'enum. Dovrebbe assomigliare a qualcosa di simile a questo:

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

Due cose da notare qui:

  1. Dichiariamo esplicitamente questi come casi enum supportati da stringhe che ci consentono di creare un'istanza con stringhe, non con altri numeri non correlati.

  2. Abbiamo aggiunto un'opzione che può o non può esistere sul nostro modello di server: UNKNOWN. Questo può essere gestito come undefinedpreferisci, ma mi piace evitare | undefinedsui tipi ogni volta che è possibile semplificare la gestione.

La cosa grandiosa di avere un UNKNOWNcaso è che puoi essere davvero ovvio a riguardo nel codice e creare stili per casi enum sconosciuti rosso vivo e lampeggiante in modo da sapere che non stai gestendo qualcosa correttamente.

Analizza l'enum

Potresti utilizzare questo enum incorporato in un altro modello, o da solo, ma dovrai analizzare l'enum tipizzato stringa-y da JSON o XML (ha) nella tua controparte fortemente tipizzata. Se incorporato in un altro modello, questo parser vive nel costruttore della classe.

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

  return type;
}

Se l'enum viene analizzato correttamente, finirà per essere il tipo corretto. Altrimenti, lo sarà undefinede puoi intercettarlo e restituire il UNKNOWNcaso. Se si preferisce utilizzare undefinedcome caso sconosciuto, è possibile restituire qualsiasi risultato dal tentativo di analisi enum.

Da lì, si tratta solo di utilizzare la funzione di analisi e di utilizzare la variabile tipizzata di recente.

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

6
Sfortunatamente, questo sembra non essere corretto o, almeno, non generalizzabile. Funziona perché le tue chiavi sono uguali alle stringhe che sono state assegnate. Se, come nel mio caso, differiscono, tuttavia, questo non funziona. Nelle parole della documentazione : "Tieni presente che i membri di enum string non ottengono affatto una mappatura inversa". Il tuo codice verrà compilato in qualcosa del genere IssueType["REPS"]="REPS". Se avessi definito il tuo enum un po 'diverso, diciamo, REPS="reps"questo produrrebbe IssueType["REPS"]="reps"che ...
Altocumulus,

... torna sempre IssueType.UNKNOWNperché non c'è chiave repsnel tuo enum. Peccato, non ho ancora trovato una soluzione funzionante per questo poiché le mie stringhe contengono trattini che li rendono inutilizzabili come chiavi.
Altocumulus,

Alla fine, ho trovato una soluzione in questa risposta convincendo il compilatore che questa non era una enumerazione di stringhe. Potrebbe valere la pena modificare queste informazioni nella tua risposta.
Altocumulus,

7

Stavo cercando una risposta che potesse ottenere un enumda a string, ma nel mio caso i valori di enum avevano una controparte di valori di stringa diversi. L'OP aveva un enum semplice per Color, ma avevo qualcosa di diverso:

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

Quando si tenta di risolvere Gender.CantTellcon una "Can't tell"stringa, viene restituito undefinedcon la risposta originale.

Un'altra risposta

Fondamentalmente, ho trovato un'altra risposta, fortemente ispirata da questa risposta :

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

Appunti

  • Prendiamo il primo risultato di filter, supponendo che il client stia passando una stringa valida dall'enum. In caso contrario, undefinedverrà restituito.
  • Abbiamo gettato enumObja any, perché con dattiloscritto 3.0+ (attualmente in uso tipografico 3.5), la enumObjsi risolve come unknown.

Esempio di utilizzo

const cantTellStr = "Can't tell";

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

Nota: E, come qualcuno ha sottolineato in un commento, volevo anche usare il noImplicitAny.

Versione aggiornata

Nessun cast anye digitazione corretta.

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];

Inoltre, la versione aggiornata ha un modo più semplice per chiamarla ed è più leggibile:

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

6

Avevo bisogno di sapere come superare i valori di enum (stava testando molte permutazioni di diversi enum) e ho trovato che questo funzionava bene:

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
}

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


Questa risposta è geniale! Lo adoro. Soprattutto il modo in cui si ricava un enum dalla stringa. Questo può farti risparmiare tanta digitazione durante il test di enumerazioni o altri casi.
Florian Leitgeb,

Sì, lo uso con Jest's eachper testare ogni singolo caso di enum con un solo metodo
mikeb

3

enum

enum MyEnum {
    First,
    Second,
    Three
}

Utilizzo del campione

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

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

Ignora analisi con distinzione tra maiuscole e minuscole

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;
    }
}

Chiunque abbia enum come me dovrebbe mettere return enumType[property];un caso quando il tuo oggetto enum sembraSkills = "anyvalue"
neustart47

@ neustart47 potresti per favore porre la domanda?
Очир Дармаев

non è una domanda. Ho appena menzionato alcune modifiche per chiunque stia cercando lo stesso caso che ho. La tua risposta è corretta
neustart47,

2

Gli enum creati nel modo in cui lo hai fatto vengono compilati in un oggetto che archivia sia i mapping forward (name -> value)che reverse (value -> name). Come possiamo osservare da questo screenshot di devtools di Chrome:

inserisci qui la descrizione dell'immagine

Ecco un esempio di come funziona la doppia mappatura e come eseguire il cast da uno all'altro:

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

Prova questo

var color: Color = (Color as any) ["Verde];

Funziona bene per la versione 3.5.3


0

Se stai usando gli spazi dei nomi per estendere la funzionalità del tuo enum, puoi anche fare qualcosa del genere

    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;
        }
      }
    }

e usalo in questo modo

  Color.getInstance('Red');

0

altre variazioni possono essere

const green= "Green";

const color : Color = Color[green] as Color;
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.