Como obter nomes de entradas enum?

314

Gostaria de repetir um TypeScript enume obter um nome de símbolo enumerado, por exemplo:

enum myEnum { entry1, entry2 }

for (var entry in myEnum) { 
    // use entry's name here, e.g., "entry1"
}
CalvinDale
fonte
este pequeno pacote enum-for tem getAllEnumValuese getAllEnumKeyspara o seu propósito
transang

Respostas:

256

O código que você postou funcionará; ele imprimirá todos os membros da enum, incluindo os valores dos membros da enum. Por exemplo, o seguinte código:

enum myEnum { bar, foo }

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

Irá imprimir o seguinte:

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

Se você preferir apenas os nomes dos membros, e não os valores, poderá fazer algo assim:

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

Isso imprimirá apenas os nomes:

Membro da enum: bar

Membro da enum: foo

Advertência: isso depende um pouco de detalhes da implementação: o TypeScript compila enumerações em um objeto JS com os valores de enumeração sendo membros do objeto. Se a TS decidir implementá-los de maneira diferente no futuro, a técnica acima poderá ser interrompida.

Judah Gabriel Himango
fonte
23
Para ser claro, a resposta acima ainda funciona a partir do TS 2.3. No entanto, se você usar "const enum", em vez de apenas "enum", somente então ele não funcionará. Usar const enum é basicamente dizer ao TS para fazer uma pesquisa e substituição; em todo lugar em que você usar o MyEnum.Foo, ele será substituído por um valor numérico correspondente.
Judah Gabriel Himango
Eu acho que +enumMember >= 0deveria ser isFinite(+enumMember)porque os valores negativos ou de ponto flutuante também são mapeados inversamente. ( Playground )
spenceryue 08/11/19
342

Embora a resposta já seja fornecida, quase ninguém apontou os documentos

Aqui está um trecho

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

Lembre-se de que os membros da string enum não recebem um mapeamento reverso.

shakram02
fonte
38
Ele também diz que "Lembre-se de que os membros da enum de string não recebem um mapeamento reverso".
Jbojcic
1
Que tal exibir 0ou a 1partir desta enumeração? export enum Octave { ZERO = 0, ONE = 1 }
Stephane
@jbojcic É sobre a situação enum Enum {"A"}; let nameOfA = Enum[Enum.A];:? A partir de [email protected] ele funciona muito bem para mim ...
ellockie
Que tal percorrer os valores?
shioko
55

Supondo que você se atenha às regras e produza apenas enumerações com valores numéricos, você pode usar esse código. Isso lida corretamente com o caso em que você tem um nome que é coincidentemente um 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
fonte
Aviso No texto datilografado moderno (tsc 2.5.2 atm), você nem pode ter uma sequência numérica como chave para começar. Como tal, a resposta da Himango é melhor, pois abrange todos os casos e não tem desvantagens.
srcspider
53

Para mim, uma maneira mais fácil, prática e direta de entender o que está acontecendo, é a seguinte enumeração:

enum colors { red, green, blue };

Será convertido essencialmente para isso:

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

Por isso, o seguinte será verdadeiro:

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

Isso cria uma maneira fácil de obter o nome de um enumerado da seguinte maneira:

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

Ele também cria uma boa maneira de converter uma string em um valor enumerado.

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

As duas situações acima são muito mais comuns, porque geralmente você está muito mais interessado no nome de um valor específico e na serialização de valores de maneira genérica.

Michael Erickson
fonte
49

Se você pesquisar apenas os nomes e iterar posteriormente, use:

Object.keys(myEnum).map(key => myEnum[key]).filter(value => typeof value === 'string') as string[];
Simon
fonte
13
Ou com a lib do ES2017:Object.values(myEnum).filter(value => typeof value === 'string') as string[];
None
Eu precisava criar um ditado e usei sua resposta como ponto de partida. Se alguém precisa dele,Object.values(myEnum).filter(value => typeof value === 'string').map(key => { return {id: myEnum[key], type: key }; });
Fejs
25

Com a versão 1.8.9 do TypeScript atual, uso Enums digitadas:

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

com resultados neste objeto Javascript:

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

então eu tenho que consultar através de chaves e valores e retornar apenas 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]]);
        }
    }
}

E eu recebo as chaves de opção em uma matriz:

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

Esta solução também funciona.

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

var type: ScreenType = ScreenType.Edit;

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

Outra solução interessante encontrada aqui é usar o 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']
]);

USAR

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

Deixe ts-enum-util( github , npm ) fazer o trabalho para você e forneça muitos utilitários seguros para tipos adicionais. Funciona com enumerações de seqüência de caracteres e numéricas, ignorando corretamente as entradas de pesquisa inversa de índice numérico para enumerações numéricas:

String enum:

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

Enumeração 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
fonte
9

A partir do TypeScript 2.4, a enumeração não continha mais a chave como membro. fonte do leia-me TypeScript

A ressalva é que as enumerações inicializadas por string não podem ser mapeadas reversamente para obter o nome do membro da enumeração original. Em outras palavras, você não pode escrever Colors ["RED"] para obter a string "Red".

Minha solução:

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

Você pode usar o enum-valuespacote que escrevi quando tive o mesmo problema:

Git: enum-values

var names = EnumValues.getNames(myEnum);
Slava Shpitalny
fonte
3
Você não está realmente respondendo à pergunta, seria melhor documentar sua resposta com o código / etc, mas achei o pacote útil.
lucuma
7

Com base nas respostas acima, criei esta assinatura de função de segurança de tipo:

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

o tipo de stringValsé'entry1' | 'entry2'

Veja em ação

Dmitry Efimenko
fonte
1
A função deve retornar em (keyof T)[]vez de keyof T. Além disso, exportimpede que o seu playground funcione.
Joald
7

Parece que nenhuma das respostas aqui funcionará com enumerações de caracteres em strict-mode.

Considere enum como:

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

Acessando isso com AnimalEnum["dog"] pode resultar em um erro como:

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

Solução adequada para esse caso, escreva-o como:

AnimalEnum["dog" as keyof typeof AnimalEnum]
coyer
fonte
Solução brilhante para usar o keyofwith typeof! Outra solução parece bastante opaca, mas, afinal, acho que o Typescript precisa continuar melhorando no DX - Experiência do desenvolvedor para Enum
Shaung Cheng
5

A melhor maneira que eu acho é apenas declarar os valores de enumeração desejados. Dessa forma, acessá-los é limpo e bonito (sempre).

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

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

vai produzir:

VALUE1
VALUE2
stemadsen
fonte
5

De acordo com a documentação do TypeScript, podemos fazer isso via Enum com funções estáticas.

Obter nome de enumeração com funções 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 ler mais sobre o Enum com função estática, siga o link abaixo https://basarat.gitbooks.io/typescript/docs/enums.html

Shahid Ahmad
fonte
4

A única solução que funciona para mim em todos os casos (mesmo que os valores sejam cadeias) é a seguinte:

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

Pergunta antiga, mas, por que não usar um constmapa de objetos?

Em vez de fazer isso:

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]

Faça isso (preste atenção ao 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
fonte
Me corrigir se estou errado, mas console.log(Object.keys(Foo))no primeiro exemplo apenas retornos ["BAR", "EVERYTHING_IS_TERRIBLE"]..
Peter
@ Peter, dê uma olhada aqui no playground ts , basta abrir o console e clicar em executar. Pelo menos para mim, ele imprime["60", "80", "BAR", "EVERYTHING_IS_TERRIBLE"]
Gabriel De Oliveira Rohden
1
parece que sua direita, a coisa divertida, se você mudar de números para strings que você obter o resultado que eu esperava, eu não tenho idéia porque typescript cadeia de alças e os números de forma diferente em enums ..
Peter
4

Encontrei essa pergunta pesquisando "TypeScript iterate over enum keys". Então, eu só quero postar uma solução que funcione para mim no meu caso. Talvez ajude alguém também.

Meu caso é o seguinte: quero iterar sobre cada chave enum, filtrar algumas chaves e acessar algum objeto que possua chaves como valores calculados a partir de enum. Então é assim que eu faço sem nenhum erro 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
fonte
3

Eu escrevi uma classe EnumUtil que está fazendo uma verificação de tipo pelo 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'
}

Como usá-lo:

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 as chaves NumberValueEnum: ["A", "B"]

Resultado para os valores NumberValueEnum: [0, 1]

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

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

Arnold Vakaria
fonte
2

Acho essa solução mais elegante:

for (let val in myEnum ) {

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

Exibe:

bar 
foo
Anthony Brenelière
fonte
2

Meu Enum é assim:

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

fazendo esse retorno indefinido :

UserSorting[UserSorting.SortByUpdatedAt]

Para resolver esse problema, escolho outra maneira de fazer isso usando um Pipe:

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

E para usá-lo:

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

Se você tem enum

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

Então você pode obter chave e valores como:

Object.keys(Diet).forEach((d: Diet) => {
  console.log(d); // KETO
  console.log(Diet[d]) // Ketogenic
});
clu
fonte
Isso causa um erro: 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 11/03
1

Eu escrevi uma função auxiliar para enumerar uma enumeração:

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
}

A função retorna algo que pode ser facilmente enumerado e também é convertido para o tipo de enumeração.

Russell Phillips
fonte
0

Usando uma versão atual do TypeScript, você pode usar funções como estas para mapear o Enum para um registro de sua escolha. Observe que você não pode definir valores de sequência com essas funções, pois elas procuram chaves com um valor que é um 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
fonte
0

Já existem muitas respostas aqui, mas acho que jogarei minha solução na pilha de qualquer maneira.

Parque infantil 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 maior clareza:

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

Referência para registro TypeScript

Uma boa função auxiliar:

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

// getAccountTypeName(AccountType.Twitter) === 'Twitter'
Chance
fonte
0

Para obter a lista dos valores de enum, você deve usar:

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

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

Não é exatamente a resposta da sua pergunta, mas é um truque para resolver o seu problema.

export module Gender {

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

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

}

Você pode estender seu modelo de lista da maneira que desejar.

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

Agora, você pode usá-lo desta maneira:

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
fonte