¿Cómo obtener nombres de entradas de enumeración?

314

Me gustaría iterar un TypeScript un enumtipo y obtener cada nombre de símbolo enumerado, por ejemplo:

enum myEnum { entry1, entry2 }

for (var entry in myEnum) { 
    // use entry's name here, e.g., "entry1"
}
CalvinDale
fuente
este pequeño paquete de enumeración tiene getAllEnumValuesy getAllEnumKeyspara su propósito
transang

Respuestas:

256

El código que publicaste funcionará; imprimirá todos los miembros de la enumeración, incluidos los valores de los miembros de la enumeración. Por ejemplo, el siguiente código:

enum myEnum { bar, foo }

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

Imprimirá lo siguiente:

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

Si, en cambio, solo desea los nombres de los miembros y no los valores, puede hacer algo como esto:

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

Eso imprimirá solo los nombres:

Miembro de Enum: bar

Miembro de Enum: foo

Advertencia: esto se basa ligeramente en un detalle de implementación: TypeScript compila enumeraciones a un objeto JS con los valores de enumeración como miembros del objeto. Si TS decidiera implementarlos de manera diferente en el futuro, la técnica anterior podría romperse.

Judá Gabriel Himango
fuente
23
Para ser claros, la respuesta anterior todavía funciona a partir de TS 2.3. Sin embargo, si usa "const enum", en lugar de solo "enum", solo entonces no funcionará. Usar const enum es básicamente decirle a TS que haga una búsqueda y reemplazo; cada lugar que use MyEnum.Foo, se reemplazará con un valor numérico correspondiente.
Judá Gabriel Himango
Creo que +enumMember >= 0debería deberse a isFinite(+enumMember)que los valores negativos o de coma flotante también se asignan inversamente. (
Zona de
342

Aunque la respuesta ya está provista, casi nadie señaló el documentos

Aquí hay un fragmento

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

Tenga en cuenta que los miembros de cadena de enumeración no obtienen una asignación inversa generada en absoluto.

shakram02
fuente
38
También dice allí "Tenga en cuenta que los miembros de enum de cadena no obtienen una asignación inversa generada en absoluto".
jbojcic
1
¿Qué hay de mostrar 0o 1de esta enumeración? export enum Octave { ZERO = 0, ONE = 1 }
Stephane
@jbojcic ¿Se trata de la situación enum Enum {"A"}; let nameOfA = Enum[Enum.A];? A partir de [email protected] funciona bien para mí ...
ellockie
¿Qué hay de recorrer los valores?
Shioko
55

Suponiendo que se apega a las reglas y solo produce enumeraciones con valores numéricos, puede usar este código. Esto maneja correctamente el caso en el que tiene un nombre que coincidentemente es un número válido

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
fuente
Advertencia En el mecanografiado moderno (tsc 2.5.2 atm) ni siquiera se le permite tener una cadena numérica como clave para empezar. Como tal, la respuesta de Himango es mejor, ya que cubre todos los casos y no tiene inconvenientes.
srcspider
53

Para mí, una forma más fácil, práctica y directa de entender lo que está sucediendo es la siguiente enumeración:

enum colors { red, green, blue };

Se convertirá esencialmente a esto:

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

Debido a esto, lo siguiente será cierto:

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

Esto crea una manera fácil de obtener el nombre de un enumerado de la siguiente manera:

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

También crea una buena manera de convertir una cadena en un valor enumerado.

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

Las dos situaciones anteriores son una situación mucho más común, porque generalmente está mucho más interesado en el nombre de un valor específico y en la serialización de valores de forma genérica.

Michael Erickson
fuente
49

Si solo busca los nombres e itera más tarde, use:

Object.keys(myEnum).map(key => myEnum[key]).filter(value => typeof value === 'string') as string[];
Simón
fuente
13
O con la biblioteca ES2017:Object.values(myEnum).filter(value => typeof value === 'string') as string[];
Ninguno
Necesitaba crear un dict, y usé tu respuesta como punto de partida. Si alguien más lo necesita,Object.values(myEnum).filter(value => typeof value === 'string').map(key => { return {id: myEnum[key], type: key }; });
Fejs
o simplemente Object.values ​​(myEnum) .filter (isNaN) como string [];
ihorbond hace
25

Con la versión actual de TypeScript 1.8.9 utilizo enumeraciones escritas:

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

con resultados en este objeto Javascript:

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

así que tengo que consultar a través de claves y valores y solo devolver valores:

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

Y recibo las teclas de opción en una matriz:

optionNames = [ "OPTION1", "OPTION2" ];
Philip
fuente
17

Esta solución también funciona.

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

var type: ScreenType = ScreenType.Edit;

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

Otra solución interesante que se encuentra aquí es usar 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']
]);

UTILIZAR

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

Deje que ts-enum-util( github , npm ) haga el trabajo por usted y proporcione muchas utilidades adicionales de tipo seguro. Funciona con cadenas y enumeraciones numéricas, ignorando adecuadamente las entradas de búsqueda inversa de índice numérico para enumeraciones numéricas:

Enum de cadena:

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();

Enumeración numérica:

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

A partir de TypeScript 2.4, la enumeración ya no contendría la clave como miembro. fuente del archivo Léame de TypeScript

La advertencia es que las enumeraciones inicializadas en cadena no se pueden asignar de forma inversa para obtener el nombre del miembro de enumeración original. En otras palabras, no puede escribir Colors ["RED"] para obtener la cadena "Red".

Mi solución:

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

Puedes usar el enum-values paquete que escribí cuando tuve el mismo problema:

Git: enum-values

var names = EnumValues.getNames(myEnum);
Slava Shpitalny
fuente
3
Realmente no está respondiendo la pregunta, sería mejor documentar su respuesta con código / etc., pero el paquete me pareció útil.
lucuma
7

Basado en algunas respuestas anteriores, se me ocurrió esta firma de función de tipo seguro:

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

Uso:

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

el tipo de stringValses'entry1' | 'entry2'

Véalo en acción

Dmitry Efimenko
fuente
1
La función debería volver en (keyof T)[]lugar de keyof T. Además, exportevita que su patio de recreo funcione.
Joald
7

Parece que ninguna de las respuestas aquí funcionará con enums de cadena en strictmodo.

Considere enum como:

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

Acceder a esto con AnimalEnum["dog"]puede provocar un error como:

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

Solución adecuada para ese caso, escríbala como:

AnimalEnum["dog" as keyof typeof AnimalEnum]
coyer
fuente
Solución brillante para usar keyofcon typeof! Otra solución parece bastante opaca, pero después de todo, creo que Typecript debe seguir mejorando en DX - Developer Experience for Enum
Shaung Cheng
5

Creo que la mejor manera es declarar los valores de enumeración deseados. De esa forma, acceder a ellos es limpio y bonito (todo el tiempo).

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

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

Producirá:

VALUE1
VALUE2
Stemadsen
fuente
5

De acuerdo con la documentación de TypeScript, podemos hacer esto a través de Enum con funciones estáticas.

Obtenga Enum Name con funciones estáticas

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 

Para leer más sobre Enum con función estática, siga el siguiente enlace https://basarat.gitbooks.io/typescript/docs/enums.html

Shahid Ahmad
fuente
4

La única solución que funciona para mí en todos los casos (incluso si los valores son cadenas) es la siguiente:

var enumToString = function(enumType, enumValue) {
    for (var enumMember in enumType) {
        if (enumType[enumMember]==enumValue) return enumMember
    }
}
usuario2080105
fuente
4

Antigua pregunta, pero, ¿por qué no usar un constmapa de objetos?

En lugar de hacer esto:

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]

Haz esto (presta atención al as constelenco):

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
fuente
Corrígeme si estoy equivocado pero console.log(Object.keys(Foo))en el primer ejemplo solo regresa ["BAR", "EVERYTHING_IS_TERRIBLE"]..
Peter
@ Peter eche un vistazo aquí en el patio de recreo ts , simplemente abra la consola y haga clic en ejecutar. Al menos para mí, imprime["60", "80", "BAR", "EVERYTHING_IS_TERRIBLE"]
Gabriel De Oliveira Rohden
1
parece correcto, lo divertido es que si cambias de números a cadenas obtienes el resultado que esperaba, no tengo idea de por qué typecript maneja las cadenas y los números de manera diferente en las enumeraciones ...
Peter
4

Encontré esta pregunta buscando "TypeScript iterate over enum keys". Así que solo quiero publicar una solución que funcione para mí en mi caso. Quizás también ayude a alguien.

Mi caso es el siguiente: quiero iterar sobre cada clave de enumeración, luego filtrar algunas claves, luego acceder a algún objeto que tenga claves como valores calculados de enumeración. Así es como lo hago sin tener ningún error de 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
fuente
3

Escribí una clase EnumUtil que está haciendo una verificación de tipo por el valor 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'
}

Cómo usarlo:

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

Resultado para las teclas NumberValueEnum: ["A", "B"]

Resultado para los valores NumberValueEnum: [0, 1]

Resultado para StringValueEnumkeys: ["A", "B"]

Resultado para StringValueEnumvalues: ["A", "B"]

Arnold Vakaria
fuente
2

Encuentro esa solución más elegante:

for (let val in myEnum ) {

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

Muestra:

bar 
foo
Anthony Brenelière
fuente
2

Mi enumeración es así:

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", 
}

haciendo este retorno indefinido :

UserSorting[UserSorting.SortByUpdatedAt]

Para resolver este problema, elijo otra forma de hacerlo usando una tubería:

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

Y para usarlo:

return this.enumKeyPipe.transform(UserSorting, [UserSorting.SortByUpdatedAt]);
Cedric Arnould
fuente
2

Si tienes enumeracion

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

Entonces puede obtener claves y valores como:

Object.keys(Diet).forEach((d: Diet) => {
  console.log(d); // KETO
  console.log(Diet[d]) // Ketogenic
});
clu
fuente
Esto causa un error: 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

Escribí una función auxiliar para enumerar una enumeración:

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

Uso:

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

La función devuelve algo que se puede enumerar fácilmente y también se convierte al tipo de enumeración.

Russell Phillips
fuente
0

Con una versión actual de TypeScript, puede utilizar funciones como estas para asignar la enumeración a un registro de su elección. Tenga en cuenta que no puede definir valores de cadena con estas funciones, ya que buscan claves con un valor que sea un número.

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
fuente
0

Ya hay muchas respuestas aquí, pero creo que arrojaré mi solución a la pila de todos modos.

Zona de juegos de 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>)

Para mayor claridad:

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

Referencia para el registro de TypeScript

Una buena función auxiliar:

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

// getAccountTypeName(AccountType.Twitter) === 'Twitter'
Oportunidad
fuente
0

Para obtener la lista de los valores de enumeración que debe usar:

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

Object.values(AnimalEnum);
Radu Linu
fuente
-1

No es exactamente la respuesta de su pregunta, pero es un truco para abordar su problema.

export module Gender {

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

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

}

Puede ampliar su modelo de lista de la forma que desee.

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

Ahora, puede usarlo de esta manera:

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

o:

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