web-dev-qa-db-fra.com

Comment convertir une chaîne enum dans TypeScript?

J'ai défini l'énumération suivante dans TypeScript:

enum Color{
    Red, Green
}

Maintenant, dans ma fonction, je reçois la couleur sous forme de chaîne. J'ai essayé le code suivant:

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

Comment puis-je convertir cette valeur en une énumération?

226
Amitabh

Les énumérations dans TypeScript 0.9 sont basées sur une chaîne + un nombre. Vous ne devriez pas avoir besoin d'assertion de type pour les conversions simples:

enum Color{
    Red, Green
}

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

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

Essayez-le en ligne

J'ai de la documentation sur cela et sur d'autres modèles Enum dans mon livre OSS: https://basarat.gitbooks.io/TypeScript/content/docs/enums.html

331
basarat

A partir de TypeScript 2.1, les clés de chaîne sont fortement typées. keyof typeof est utilisé pour obtenir des informations sur les clés de chaîne disponibles ( 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

89
Victor

Cette note se rapporte à réponse de Basarat, pas à la question initiale.

J'ai eu un problème étrange dans mon propre projet où le compilateur donnait une erreur à peu près équivalente à "ne peut pas convertir une chaîne en couleur" en utilisant l'équivalent de ce code:

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

J'ai trouvé que l'inférence du type de compilateur devenait confuse et elle pensait que colorId était une valeur enum et non un ID. Pour résoudre le problème, je devais convertir l'ID sous forme de chaîne:

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

Je ne suis pas sûr de la cause du problème, mais je laisserai cette note ici au cas où quelqu'un rencontrerait le même problème que moi.

26
Sly_cardinal

Si vous êtes certain qu'une chaîne d'entrée a une correspondance exacte avec Color enum, utilisez:

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

Dans le cas où une chaîne d'entrée peut ne pas correspondre à Enum, utilisez:

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

Terrain de je


Si nous ne convertissons pas enum en <any>, alors TypeScript affichera l'erreur:

L'élément a implicitement le type 'any' car l'expression d'index n'est pas du type 'number'.

Cela signifie que par défaut, le type TypeScript Enum fonctionne avec les index numériques, c'est-à-dire let c = Color[0], mais pas avec les index de chaîne tels que let c = Color["string"]. Il s'agit d'une restriction connue de l'équipe Microsoft pour le problème plus général Index de chaînes d'objets.

25
Artru

Je l'ai obtenu en utilisant le code suivant.

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

J'ai aussi rencontré la même erreur de compilation. Juste une légère variation plus courte de l'approche de Sly_cardinal.

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

Si le compilateur TypeScript sait que le type de variable est string, cela fonctionne:

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

Sinon, vous devriez explicitement le convertir en chaîne (pour éviter les avertissements du compilateur):

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

Au moment de l'exécution, les deux solutions fonctionneront.

9
Luka
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

Cet exemple fonctionne avec --noImplicitAny dans TypeScript

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

6
Jonas

Il y a beaucoup d'informations mitigées dans cette question, couvrons donc toute l'implémentation de TypeScript 2.x + dans Guide de Nick sur l'utilisation d'énums dans les modèles avec TypeScript.

Ce guide est destiné aux personnes qui créent un code côté client qui englobe un ensemble de chaînes connues du serveur, qui serait commodément modélisé sous la forme d’un Enum du côté client.

Définir l'énum

Commençons par l'énum. Ça devrait ressembler a quelque chose comme ca:

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

Deux choses à noter ici:

  1. Nous les déclarons explicitement comme des cas d'énumération adossés à des chaînes, ce qui nous permet de les instancier avec des chaînes, pas avec d'autres nombres non liés.

  2. Nous avons ajouté une option qui n'existe peut-être pas sur notre modèle de serveur: UNKNOWN. Ceci peut être traité comme undefined si vous préférez, mais j'aime éviter les types | undefined autant que possible pour simplifier la gestion.

Le grand avantage d'avoir un cas UNKNOWN est que vous pouvez être vraiment évident à ce sujet dans le code et créer des styles pour des cas d'enum inconnus de couleur rouge vif et clignotant, de sorte que vous sachiez que vous ne gérez pas quelque chose correctement.

Analyser l'énum

Vous utilisez peut-être cette énumération incorporée dans un autre modèle, ou toute seule, mais vous devrez analyser l'énumération chaîne-y de JSON ou XML (ha) dans votre contrepartie fortement typée. Lorsqu'il est incorporé à un autre modèle, cet analyseur réside dans le constructeur de classe.

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

  return type;
}

Si l'énumération est correctement analysée, elle finira par être du type approprié. Sinon, ce sera undefined et vous pourrez l'intercepter et renvoyer votre cas UNKNOWN. Si vous préférez utiliser undefined comme cas inconnu, vous pouvez simplement renvoyer tout résultat de l'analyse syntaxique tentée.

À partir de là, il suffit d'utiliser la fonction d'analyse et d'utiliser votre nouvelle variable typée forte.

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

J'avais besoin de savoir comment boucler les valeurs d'énum (je testais beaucoup de permutations de plusieurs énumérations) et j'ai trouvé que cela fonctionnait bien:

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
}
2
mikeb

Enum

enum MyEnum {
    First,
    Second,
    Three
}

tilisation de l'échantillon

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

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

Ignorer l'analyse sensible à la casse

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

Essaye ça

var color: Color = (Couleur comme tout) ["Vert];

Cela fonctionne bien pour la version 3.5.3

1
Oyeme

Les énumérations créées de cette manière sont compilées dans un objet qui stocke à la fois les mappages forward (name -> value) et inverses (value -> name). Comme nous pouvons le constater à partir de cette capture d'écran chrome devtools:

enter image description here

Voici un exemple du fonctionnement de la double correspondance et de la conversion de l'une à l'autre:

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
0