Comment obtenir les noms des entrées d'énumération?

315

Je voudrais itérer un TypeScript un enumtype et obtenir chaque nom de symbole énuméré, par exemple:

enum myEnum { entry1, entry2 }

for (var entry in myEnum) { 
    // use entry's name here, e.g., "entry1"
}
CalvinDale
la source
ce petit paquet enum-for a getAllEnumValueset getAllEnumKeyspour votre but
transang

Réponses:

256

Le code que vous avez publié fonctionnera; il imprimera tous les membres de l'énumération, y compris les valeurs des membres de l'énumération. Par exemple, le code suivant:

enum myEnum { bar, foo }

for (var enumMember in myEnum) {
   console.log("enum member: ", enumMember);
}

Imprime ce qui suit:

Enum member: 0
Enum member: 1
Enum member: bar
Enum member: foo

Si vous ne souhaitez que les noms de membres et non les valeurs, vous pouvez faire quelque chose comme ceci:

for (var enumMember in myEnum) {
   var isValueProperty = parseInt(enumMember, 10) >= 0
   if (isValueProperty) {
      console.log("enum member: ", myEnum[enumMember]);
   }
}

Cela n'imprimera que les noms:

Membre enum: bar

Membre enum: foo

Avertissement: cela s'appuie légèrement sur un détail d'implémentation: TypeScript compile les énumérations en un objet JS avec les valeurs d'énumération membres de l'objet. Si TS décidait de les implémenter différemment à l'avenir, la technique ci-dessus pourrait échouer.

Judah Gabriel Himango
la source
23
Pour être clair, la réponse ci-dessus fonctionne toujours à partir de TS 2.3. Cependant, si vous utilisez "const enum", plutôt que simplement "enum", alors cela ne fonctionnera pas. L'utilisation de const enum indique essentiellement à TS d'effectuer une recherche et un remplacement; chaque fois que vous utilisez MyEnum.Foo, il sera remplacé par une valeur numérique correspondante.
Judah Gabriel Himango
Je pense que cela +enumMember >= 0devrait être isFinite(+enumMember)dû au fait que les valeurs négatives ou à virgule flottante sont également inversées. ( Aire de jeux )
spenceryue
342

Bien que la réponse soit déjà fournie, presque personne n'a pointé les documents

Voici un extrait

enum Enum {
    A
}
let nameOfA = Enum[Enum.A]; // "A"

Gardez à l'esprit que les membres d'énumération de chaîne n'obtiennent pas du tout de mappage inverse.

shakram02
la source
38
Il indique également: "Gardez à l'esprit que les membres de l'énumération de chaîne ne reçoivent pas du tout de mappage inverse."
jbojcic
1
Que diriez-vous d'afficher 0ou 1de cette énumération? export enum Octave { ZERO = 0, ONE = 1 }
Stephane
@jbojcic est - il sur la situation: enum Enum {"A"}; let nameOfA = Enum[Enum.A];? À partir de [email protected] cela fonctionne très bien pour moi ...
ellockie
Que diriez-vous de parcourir les valeurs?
shioko
55

En supposant que vous respectiez les règles et ne produisiez que des énumérations avec des valeurs numériques, vous pouvez utiliser ce code. Cela gère correctement le cas où vous avez un nom qui est par coïncidence un nombre valide

enum Color {
    Red,
    Green,
    Blue,
    "10" // wat
}

var names: string[] = [];
for(var n in Color) {
    if(typeof Color[n] === 'number') names.push(n);
}
console.log(names); // ['Red', 'Green', 'Blue', '10']
Ryan Cavanaugh
la source
Avertissement Dans le typographie moderne (tsc 2.5.2 atm), vous n'êtes même pas autorisé à avoir une chaîne numérique comme clé pour commencer. En tant que tel, la réponse d'Himango est meilleure, car elle couvre tous les cas et n'a aucun inconvénient.
srcspider
53

Pour moi, une façon plus simple, pratique et directe de comprendre ce qui se passe, c'est que l'énumération suivante:

enum colors { red, green, blue };

Sera converti essentiellement en ceci:

var colors = { red: 0, green: 1, blue: 2,
               [0]: "red", [1]: "green", [2]: "blue" }

Pour cette raison, ce qui suit sera vrai:

colors.red === 0
colors[colors.red] === "red"
colors["red"] === 0

Cela crée un moyen facile d'obtenir le nom d'un énuméré comme suit:

var color: colors = colors.red;
console.log("The color selected is " + colors[color]);

Il crée également un bon moyen de convertir une chaîne en une valeur énumérée.

var colorName: string = "green";
var color: colors = colors.red;
if (colorName in colors) color = colors[colorName];

Les deux situations ci-dessus sont une situation beaucoup plus courante, car généralement vous êtes beaucoup plus intéressé par le nom d'une valeur spécifique et la sérialisation des valeurs de manière générique.

Michael Erickson
la source
49

Si vous recherchez uniquement les noms et que vous réitérez ultérieurement, utilisez:

Object.keys(myEnum).map(key => myEnum[key]).filter(value => typeof value === 'string') as string[];
Simon
la source
13
Ou avec la bibliothèque ES2017:Object.values(myEnum).filter(value => typeof value === 'string') as string[];
Aucune
J'avais besoin de créer un dict, et j'ai utilisé votre réponse comme point de départ. Si quelqu'un d'autre en a besoin,Object.values(myEnum).filter(value => typeof value === 'string').map(key => { return {id: myEnum[key], type: key }; });
Fejs
ou juste Object.values ​​(myEnum) .filter (isNaN) as string [];
ihorbond Il y a
25

Avec la version 1.8.9 de TypeScript actuelle, j'utilise des énumérations typées:

export enum Option {
    OPTION1 = <any>'this is option 1',
    OPTION2 = <any>'this is option 2'
}

avec des résultats dans cet objet Javascript:

Option = {
    "OPTION1": "this is option 1",
    "OPTION2": "this is option 2",
    "this is option 1": "OPTION1",
    "this is option 2": "OPTION2"
}

donc je dois interroger les clés et les valeurs et ne retourner que les valeurs:

let optionNames: Array<any> = [];    
for (let enumValue in Option) {
    let optionNameLength = optionNames.length;

    if (optionNameLength === 0) {
        this.optionNames.push([enumValue, Option[enumValue]]);
    } else {
        if (this.optionNames[optionNameLength - 1][1] !== enumValue) {
            this.optionNames.push([enumValue, Option[enumValue]]);
        }
    }
}

Et je reçois les clés d'option dans un tableau:

optionNames = [ "OPTION1", "OPTION2" ];
Philippe
la source
17

Cette solution fonctionne aussi.

enum ScreenType {
    Edit = 1,
    New = 2,
    View = 4
}

var type: ScreenType = ScreenType.Edit;

console.log(ScreenType[type]); //Edit
Carlinhos
la source
14

Une autre solution intéressante trouvée ici utilise ES6 Map:

export enum Type {
  low,
  mid,
  high
}

export const TypeLabel = new Map<number, string>([
  [Type.low, 'Low Season'],
  [Type.mid, 'Mid Season'],
  [Type.high, 'High Season']
]);

UTILISATION

console.log(TypeLabel.get(Type.low)); // Low Season
manzapanza
la source
10

Laissez ts-enum-util( github , npm ) faire le travail pour vous et fournissez de nombreux utilitaires de type sécurisé supplémentaires. Fonctionne avec les énumérations de chaîne et numériques, en ignorant correctement les entrées de recherche inversée d'index numérique pour les énumérations numériques:

Énumération des chaînes:

import {$enum} from "ts-enum-util";

enum Option {
    OPTION1 = 'this is option 1',
    OPTION2 = 'this is option 2'
}

// type: ("OPTION1" | "OPTION2")[]
// value: ["OPTION1", "OPTION2"]
const keys= $enum(Option).getKeys();

// type: Option[]
// value: ["this is option 1", "this is option 2"]
const values = $enum(Option).getValues();

Énumération numérique:

enum Option {
    OPTION1,
    OPTION2
}

// type: ("OPTION1" | "OPTION2")[]
// value: ["OPTION1", "OPTION2"]
const keys= $enum(Option).getKeys();

// type: Option[]
// value: [0, 1]
const values = $enum(Option).getValues();
Jeff Lau
la source
9

À partir de TypeScript 2.4, l'énumération ne contiendrait plus la clé en tant que membre. source du fichier Lisez-moi TypeScript

La mise en garde est que les énumérations initialisées par une chaîne ne peuvent pas être mappées en sens inverse pour obtenir le nom de membre de l'énumération d'origine. En d'autres termes, vous ne pouvez pas écrire Couleurs ["ROUGE"] pour obtenir la chaîne "Rouge".

Ma solution:

export const getColourKey = (value: string ) => {
    let colourKey = '';
    for (const key in ColourEnum) {
        if (value === ColourEnum[key]) {
            colourKey = key;
            break;
        }
    }
    return colourKey;
};
kitko112
la source
8

Vous pouvez utiliser le enum-valuespackage que j'ai écrit lorsque j'ai eu le même problème:

Git: enum-values

var names = EnumValues.getNames(myEnum);
Slava Shpitalny
la source
3
Vous ne répondez pas vraiment à la question, il serait préférable de documenter votre réponse avec le code / etc mais j'ai trouvé le paquet utile.
lucuma
7

Sur la base de certaines réponses ci-dessus, j'ai trouvé cette signature de fonction de type sécurisé:

export function getStringValuesFromEnum<T>(myEnum: T): keyof T {
  return Object.keys(myEnum).filter(k => typeof (myEnum as any)[k] === 'number') as any;
}

Usage:

enum myEnum { entry1, entry2 };
const stringVals = getStringValuesFromEnum(myEnum);

le type de stringValsest'entry1' | 'entry2'

Voyez-le en action

Dmitry Efimenko
la source
1
La fonction doit retourner (keyof T)[]au lieu de keyof T. De plus, cela exportempêche votre terrain de jeu de fonctionner.
Joald
7

Il semble qu'aucune des réponses ici ne fonctionnera avec des stricténumérations de chaînes en mode.

Considérez enum comme:

enum AnimalEnum {
  dog = "dog", cat = "cat", mouse = "mouse"
}

Accéder à cela avec AnimalEnum["dog"] peut entraîner une erreur comme:

Element implicitly has an 'any' type because expression of type 'any' can't be used to index type 'typeof AnimalEnum'.ts(7053).

Solution appropriée pour ce cas, écrivez-la comme suit:

AnimalEnum["dog" as keyof typeof AnimalEnum]
coyer
la source
Excellente solution pour utiliser le keyofavec typeof! Une autre solution semble assez opaque, mais après tout, je pense que Typescript doit continuer à s'améliorer sur DX - Developer Experience for Enum
Shaung Cheng
5

La meilleure façon, je pense, est de simplement déclarer les valeurs d'énumération souhaitées. De cette façon, y accéder est propre et joli (à chaque fois).

enum myEnum { entry1 = 'VALUE1', entry2 = 'VALUE2' }

for (var entry in myEnum) { 
    console.log(entry);
}

produira:

VALUE1
VALUE2
stemadsen
la source
5

Selon la documentation TypeScript, nous pouvons le faire via Enum avec des fonctions statiques.

Obtenir un nom enum avec des fonctions statiques

enum myEnum { 
    entry1, 
    entry2 
}

namespace myEnum {
    export function GetmyEnumName(m: myEnum) {
      return myEnum[m];
    }
}


now we can call it like below
myEnum.GetmyEnumName(myEnum.entry1);
// result entry1 

pour en savoir plus sur Enum avec fonction statique, suivez le lien ci-dessous https://basarat.gitbooks.io/typescript/docs/enums.html

Shahid Ahmad
la source
4

La seule solution qui fonctionne pour moi dans tous les cas (même si les valeurs sont des chaînes) est la suivante:

var enumToString = function(enumType, enumValue) {
    for (var enumMember in enumType) {
        if (enumType[enumMember]==enumValue) return enumMember
    }
}
user2080105
la source
4

Vieille question, mais pourquoi ne pas utiliser un const carte d'objets?

Au lieu de faire ceci:

enum Foo {
    BAR = 60,
    EVERYTHING_IS_TERRIBLE = 80
}

console.log(Object.keys(Foo))
// -> ["60", "80", "BAR", "EVERYTHING_IS_TERRIBLE"]
console.log(Object.values(Foo))
// -> ["BAR", "EVERYTHING_IS_TERRIBLE", 60, 80]

Faites ceci (faites attention à la as constdistribution):

const Foo = {
    BAR: 60,
    EVERYTHING_IS_TERRIBLE: 80
} as const

console.log(Object.keys(Foo))
// -> ["BAR", "EVERYTHING_IS_TERRIBLE"]
console.log(Object.values(Foo))
// -> [60, 80]
Gabriel De Oliveira Rohden
la source
Corrigez-moi si je me trompe mais console.log(Object.keys(Foo))dans le premier exemple ne revient que ["BAR", "EVERYTHING_IS_TERRIBLE"]..
Peter
@Peter donne un coup d'oeil ici à l'aire de jeux ts , il suffit d'ouvrir la console et de cliquer sur run. Au moins pour moi, il imprime["60", "80", "BAR", "EVERYTHING_IS_TERRIBLE"]
Gabriel De Oliveira Rohden
1
il semble que vous ayez raison, la chose amusante si vous changez de nombres en chaînes vous obtenez la sortie à laquelle je m'attendais, je ne sais pas pourquoi dactylographie gère les chaînes et les nombres différemment dans les énumérations ..
Peter
4

J'ai trouvé cette question en recherchant "TypeScript itérer sur les clés enum". Je veux donc simplement publier une solution qui fonctionne pour moi dans mon cas. Peut-être que cela aidera aussi quelqu'un.

Mon cas est le suivant: je veux parcourir chaque clé enum, puis filtrer certaines clés, puis accéder à un objet qui a des clés comme valeurs calculées à partir d'énum. Voilà donc comment je le fais sans avoir d'erreur TS.

    enum MyEnum = { ONE = 'ONE', TWO = 'TWO' }
    const LABELS = {
       [MyEnum.ONE]: 'Label one',
       [MyEnum.TWO]: 'Label two'
    }


    // to declare type is important - otherwise TS complains on LABELS[type]
    // also, if replace Object.values with Object.keys - 
    // - TS blames wrong types here: "string[] is not assignable to MyEnum[]"
    const allKeys: Array<MyEnum> = Object.values(MyEnum)

    const allowedKeys = allKeys.filter(
      (type) => type !== MyEnum.ONE
    )

    const allowedLabels = allowedKeys.map((type) => ({
      label: LABELS[type]
    }))
Alendorff
la source
3

J'ai écrit une classe EnumUtil qui vérifie le type par la valeur enum:

export class EnumUtils {
  /**
   * Returns the enum keys
   * @param enumObj enum object
   * @param enumType the enum type
   */
  static getEnumKeys(enumObj: any, enumType: EnumType): any[] {
    return EnumUtils.getEnumValues(enumObj, enumType).map(value => enumObj[value]);
  }

  /**
   * Returns the enum values
   * @param enumObj enum object
   * @param enumType the enum type
   */
  static getEnumValues(enumObj: any, enumType: EnumType): any[] {
    return Object.keys(enumObj).filter(key => typeof enumObj[key] === enumType);
  }
}

export enum EnumType {
  Number = 'number',
  String = 'string'
}

Comment l'utiliser:

enum NumberValueEnum{
  A= 0,
  B= 1
}

enum StringValueEnum{
  A= 'A',
  B= 'B'
}

EnumUtils.getEnumKeys(NumberValueEnum, EnumType.number);
EnumUtils.getEnumValues(NumberValueEnum, EnumType.number);

EnumUtils.getEnumKeys(StringValueEnum, EnumType.string);
EnumUtils.getEnumValues(StringValueEnum, EnumType.string);

Résultat pour les clés NumberValueEnum: ["A", "B"]

Résultat pour les valeurs NumberValueEnum: [0, 1]

Résultat pour StringValueEnumkeys: ["A", "B"]

Résultat pour StringValueEnumvalues: ["A", "B"]

Arnold Vakaria
la source
2

Je trouve cette solution plus élégante:

for (let val in myEnum ) {

 if ( isNaN( parseInt( val )) )
     console.log( val );
}

Il affiche:

bar 
foo
Anthony Brenelière
la source
2

Mon Enum est comme ceci:

export enum UserSorting {
    SortByFullName = "Sort by FullName", 
    SortByLastname = "Sort by Lastame", 
    SortByEmail = "Sort by Email", 
    SortByRoleName = "Sort by Role", 
    SortByCreatedAt = "Sort by Creation date", 
    SortByCreatedBy = "Sort by Author", 
    SortByUpdatedAt = "Sort by Edit date", 
    SortByUpdatedBy = "Sort by Editor", 
}

faisant ce retour non défini :

UserSorting[UserSorting.SortByUpdatedAt]

Pour résoudre ce problème, je choisis une autre façon de le faire à l'aide d'un tuyau:

import { Pipe, PipeTransform } from '@angular/core';

@Pipe({
    name: 'enumKey'
})
export class EnumKeyPipe implements PipeTransform {

  transform(value, args: string[] = null): any {
    let enumValue = args[0];
    var keys = Object.keys(value);
    var values = Object.values(value);
    for (var i = 0; i < keys.length; i++) {
      if (values[i] == enumValue) {
        return keys[i];
      }
    }
    return null;
    }
}

Et pour l'utiliser:

return this.enumKeyPipe.transform(UserSorting, [UserSorting.SortByUpdatedAt]);
Cédric Arnould
la source
2

Si vous avez une énumération

enum Diet {
  KETO = "Ketogenic",
  ATKINS = "Atkins",
  PALEO = "Paleo",
  DGAF = "Whatever"
}

Ensuite, vous pouvez obtenir des clés et des valeurs comme:

Object.keys(Diet).forEach((d: Diet) => {
  console.log(d); // KETO
  console.log(Diet[d]) // Ketogenic
});
clu
la source
Cela provoque une erreur: Argument of type '(d: Diet) => void' is not assignable to parameter of type '(value: string, index: number, array: string[]) => void'. Types of parameters 'd' and 'value' are incompatible. Type 'string' is not assignable to type 'MyEnum'.(2345)
jrheling
1

J'ai écrit une fonction d'aide pour énumérer une énumération:

static getEnumValues<T extends number>(enumType: {}): T[] {
  const values: T[] = [];
  const keys = Object.keys(enumType);
  for (const key of keys.slice(0, keys.length / 2)) {
    values.push(<T>+key);
  }
  return values;
}

Usage:

for (const enumValue of getEnumValues<myEnum>(myEnum)) {
  // do the thing
}

La fonction renvoie quelque chose qui peut être facilement énuméré, et convertit également le type enum.

Russell Phillips
la source
0

En utilisant une version actuelle de TypeScript, vous pouvez utiliser des fonctions comme celles-ci pour mapper l'énumération à un enregistrement de votre choix. Notez que vous ne pouvez pas définir de valeurs de chaîne avec ces fonctions car elles recherchent des clés avec une valeur qui est un nombre.

enum STATES {
  LOGIN,
  LOGOUT,
}

export const enumToRecordWithKeys = <E extends any>(enumeration: E): E => (
  Object.keys(enumeration)
    .filter(key => typeof enumeration[key] === 'number')
    .reduce((record, key) => ({...record, [key]: key }), {}) as E
);

export const enumToRecordWithValues = <E extends any>(enumeration: E): E => (
  Object.keys(enumeration)
    .filter(key => typeof enumeration[key] === 'number')
    .reduce((record, key) => ({...record, [key]: enumeration[key] }), {}) as E
);

const states = enumToRecordWithKeys(STATES)
const statesWithIndex = enumToRecordWithValues(STATES)

console.log(JSON.stringify({
  STATES,
  states,
  statesWithIndex,
}, null ,2));

// Console output:
{
  "STATES": {
    "0": "LOGIN",
    "1": "LOGOUT",
    "LOGIN": 0,
    "LOGOUT": 1
  },
  "states": {
    "LOGIN": "LOGIN",
    "LOGOUT": "LOGOUT"
  },
  "statesWithIndex": {
    "LOGIN": 0,
    "LOGOUT": 1
  }
}
geschwe1
la source
0

Il y a déjà beaucoup de réponses ici, mais je pense que je vais quand même jeter ma solution sur la pile.

Aire de jeux TypeScript

enum AccountType {
  Google = 'goo',
  Facebook = 'boo',
  Twitter = 'wit',
}

type Key = keyof typeof AccountType // "Google" | "Facebook" | "Twitter"

// this creates a POJO of the enum "reversed" using TypeScript's Record utility
const reversed = (Object.keys(AccountType) as Key[]).reduce((acc, key) => {
  acc[AccountType[key]] = key
  return acc
}, {} as Record<AccountType, string>)

Pour plus de clarté:

/*
 * reversed == {
 *   "goo": "Google",
 *   "boo": "Facebook",
 *   "wit": "Twitter",
 * }
 * reversed[AccountType.Google] === "Google" 👍
 */

Référence pour enregistrement TypeScript

Une belle fonction d'aide:

const getAccountTypeName = (type: AccountType) => {
  return reversed[type]
};

// getAccountTypeName(AccountType.Twitter) === 'Twitter'
Chance
la source
0

Pour obtenir la liste des valeurs d'énumération que vous devez utiliser:

enum AnimalEnum {
  DOG = "dog", 
  CAT = "cat", 
  MOUSE = "mouse"
}

Object.values(AnimalEnum);
Radu Linu
la source
-1

Ce n'est pas exactement la réponse à votre question, mais c'est une astuce pour résoudre votre problème.

export module Gender {

  export enum Type {
    Female = 1,
    Male = 2
  };

  export const List = Object.freeze([
    Type[Type.Female] ,
    Type[Type.Male]
  ]);

}

Vous pouvez étendre votre modèle de liste comme vous le souhaitez.

export const List = Object.freeze([
    { name: Type[Type.Female], value: Type.Female } ,
    { name: Type[Type.Male], value: Type.Male }
  ]);

Maintenant, vous pouvez l'utiliser de cette façon:

for(const gender of Gender.List){
  console.log(gender.name);
  console.log(gender.value);
}

ou:

if(i === Gender.Type.Male){
  console.log("I am a man.");
}
Pedram Ahmadpour
la source