Як отримати назви записів enum?


314

Я хотів би ввести TypeScript і enum тип і отримати кожне перелічене ім'я символу, наприклад:

enum myEnum { entry1, entry2 }

for (var entry in myEnum) { 
    // use entry's name here, e.g., "entry1"
}

цей крихітний пакет для перерахування має getAllEnumValuesі getAllEnumKeysдля вашої мети
трансанг

Відповіді:


255

Код, який ви опублікували, буде працювати; він виведе всіх членів enum, включаючи значення членів enum. Наприклад, наступний код:

enum myEnum { bar, foo }

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

Буде надруковано наступне:

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

Якщо ви хочете отримати лише імена членів, а не значення, ви можете зробити щось подібне:

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

Це буде друкувати лише імена:

Член Enum: бар

Член Enum: foo

Caveat: це трохи покладається на деталі реалізації: TypeScript компілює перерахунки до JS-об'єкта, при цьому значення enum є членами об'єкта. Якщо TS вирішив впроваджувати їх в майбутньому різними, вищезгадана методика може зламатись.


23
Зрозуміло, що вищевказана відповідь все ще працює, як у TS 2.3. Однак якщо ви використовуєте "const enum", а не просто "enum", тільки тоді це не вийде. Використання const enum - це в основному команда TS зробити пошук і заміну; кожне місце, де ви використовуєте MyEnum.Foo, воно буде замінено відповідним числовим значенням.
Іуда Габріель Хіманго

Я думаю, що це +enumMember >= 0повинно бути, isFinite(+enumMember)тому що негативні значення чи значення з плаваючою точкою також відображаються на зворотному рівні. ( Ігровий майданчик )
spenceryue

341

Хоча відповідь уже надана, майже ніхто не вказав на документи

Ось фрагмент

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

Майте на увазі, що члени перерахунків рядків взагалі не отримують зворотного відображення.


38
Там також сказано: "Майте на увазі, що члени перерахунків рядків взагалі не отримують зворотне відображення".
jbojcic

1
Як щодо відображення 0чи 1з цього перерахунку? export enum Octave { ZERO = 0, ONE = 1 }
Стефан

@jbojcic Це стосується ситуації enum Enum {"A"}; let nameOfA = Enum[Enum.A];:? Що стосується
typecript@2.9.2,

Як щодо перегляду значень?
shioko

55

Якщо припустити, що ви дотримуєтесь правил і створюєте лише перерахунки з числовими значеннями, ви можете використовувати цей код. Це правильно обробляє випадок, коли у вас є ім'я, яке збігається випадково

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

Попередження У сучасному машинописі (tsc 2.5.2 атм) вам навіть заборонено мати числовий рядок як ключ. Відповідь Хіманго відповідь краща, оскільки вона охоплює всі випадки і не має недоліків.
srcspider

52

Для мене більш простим, практичним і прямим способом зрозуміти, що відбувається, є наступне перерахування:

enum colors { red, green, blue };

Буде перетворено по суті на це:

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

Через це буде вірно наступне:

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

Це створює простий спосіб отримати назву переліченого таким чином:

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

Це також створює хороший спосіб перетворення рядка в перелічене значення.

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

Дві ситуації вище - це набагато частіша ситуація, тому що зазвичай вас набагато більше цікавить назва конкретного значення та серіалізує значення у загальному вигляді.


49

Якщо ви шукаєте лише імена та пізніше повторіть використання:

Object.keys(myEnum).map(key => myEnum[key]).filter(value => typeof value === 'string') as string[];

13
Або з lib ES2017:Object.values(myEnum).filter(value => typeof value === 'string') as string[];
Немає

Мені потрібно було створити диктант, і я використав вашу відповідь як вихідну точку. Якщо комусь це потрібно,Object.values(myEnum).filter(value => typeof value === 'string').map(key => { return {id: myEnum[key], type: key }; });
Fejs

25

З поточною версією TypeScript 1.8.9 я використовую набрані Enums:

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

з результатами в цьому об’єкті Javascript:

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

тому я повинен запитувати ключі та значення та повертати лише значення:

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

І я отримую параметри ключів у масиві:

optionNames = [ "OPTION1", "OPTION2" ];


17

Це рішення теж працює.

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

var type: ScreenType = ScreenType.Edit;

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

14

Ще одне цікаве рішення, знайдене тут, - використання 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']
]);

ВИКОРИСТАННЯ

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

10

Нехай ts-enum-util( github , npm ) виконати роботу за вас і забезпечити безліч додаткових утиліт тип. Працює як з рядковими, так і з числовими перерахунками, правильно ігноруючи записи зворотного пошуку числових індексів для числових перерахунків:

Рядок перерахунку:

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

Числовий перелік:

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

9

Починаючи з TypeScript 2.4, enum більше не міститиме ключ як член. джерело з TypeScript readme

Застереження полягає в тому, що ініціалізовані рядки перерахунки не можуть бути зворотно відображені для отримання оригінального імені члена enum. Іншими словами, ви не можете написати Colors ["RED"], щоб отримати рядок "Red".

Моє рішення:

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

8

Ви можете використовувати enum-valuesпакет, який я написав, коли у мене була така ж проблема:

Git: enum-значення

var names = EnumValues.getNames(myEnum);

3
Ви справді не відповідаєте на питання, було б краще задокументувати свою відповідь кодом / тощо, але я вважав пакет корисним.
lucuma

7

На підставі деяких відповідей вище, я придумав цю функцію безпечної для підпису функції:

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

Використання:

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

тип stringValsє'entry1' | 'entry2'

Побачити це в дії


1
Функція повинна повертатися (keyof T)[]замість keyof T. Також exportзупиняє роботу вашого дитячого майданчика.
Джоалд

7

Здається, жодна відповідь тут не працюватиме з string-enums в -mode strict.

Розгляньте перелік як:

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

Доступ до цього с AnimalEnum["dog"] може призвести до помилки на зразок:

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

Правильне рішення для цього випадку, запишіть його як:

AnimalEnum["dog" as keyof typeof AnimalEnum]

Блискуче рішення для використання keyofз typeof! Інше рішення здається досить непрозорим, але зрештою, я думаю, що Typescript повинен продовжувати вдосконалюватись на DX - Досвід розробників для Enum
Shaung Cheng

5

Найкращий спосіб, на який я думаю, - це просто оголосити бажані значення перерахунків. Таким чином, доступ до них чистий і гарний (кожен раз).

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

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

буде виробляти:

VALUE1
VALUE2

5

Згідно з документацією TypeScript, ми можемо це зробити за допомогою Enum зі статичними функціями.

Отримати ім'я Enum зі статичними функціями

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 

Щоб дізнатися більше про Enum зі статичною функцією, перейдіть за посиланням нижче https://basarat.gitbooks.io/typescript/docs/enums.html


4

Єдине рішення, яке працює для мене у всіх випадках (навіть якщо значення є рядками), це наступне:

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

4

Старе питання, але, чому не використовувати a const об’єктну карту?

Замість цього:

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]

Зробіть це (зверніть увагу на as constакторський склад ):

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]

Виправте мене, якщо я помиляюся, але console.log(Object.keys(Foo))в першому прикладі тільки повертається ["BAR", "EVERYTHING_IS_TERRIBLE"]..
Петро

@ Петер подивіться тут на ігровий майданчик , просто відкрийте консоль і натисніть на біг. Принаймні для мене це друкує["60", "80", "BAR", "EVERYTHING_IS_TERRIBLE"]
Габріель Де Олівейра Роден

1
здається, ваше право, цікаво, якщо ви переходите від чисел до рядків, ви отримуєте результат, який я очікував, я не маю уявлення, чому машинопис обробляє рядок і числа по-різному в перерахунках ..
Петро

4

Я знайшов це питання за допомогою пошуку "TypeScript ітерації за перерахуванням ключів". Тому я просто хочу розмістити рішення, яке працює для мене в моєму випадку. Можливо, це теж допоможе комусь.

Моя справа така: я хочу повторити кожну клавішу перерахунку, потім відфільтрувати деякі клавіші, а потім отримати доступ до деякого об'єкта, у якого є ключі як обчислені значення з enum. Так це я роблю, не маючи жодної помилки 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]
    }))

3

Я написав клас EnumUtil, який здійснює перевірку типу за значенням 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'
}

Як ним користуватися:

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

Результат для клавіш NumberValueEnum: ["A", "B"]

Результат для значень NumberValueEnum: [0, 1]

Результат для StringValueEnumkeys: ["A", "B"]

Результат для StringValueEnumvalues: ["A", "B"]


2

Я вважаю це рішення більш елегантним:

for (let val in myEnum ) {

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

На ньому відображаються:

bar 
foo

2

Мій Енум такий:

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

таким чином, це повернення не визначено :

UserSorting[UserSorting.SortByUpdatedAt]

Щоб вирішити цю проблему, я вибираю інший спосіб зробити це за допомогою Труби:

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

І використовувати його:

return this.enumKeyPipe.transform(UserSorting, [UserSorting.SortByUpdatedAt]);

2

Якщо у вас є перерахунки

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

Тоді ви можете отримати ключ і значення, такі як:

Object.keys(Diet).forEach((d: Diet) => {
  console.log(d); // KETO
  console.log(Diet[d]) // Ketogenic
});

Це спричиняє помилку: 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)
кричав

1

Я написав функцію помічника для перерахування переліку:

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

Використання:

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

Функція повертає те, що можна легко перерахувати, а також передає типу enum.


0

Використовуючи поточну версію TypeScript, ви можете використовувати такі функції, як мапа Enum для запису на ваш вибір. Зауважте, що ви не можете визначити значення рядків за допомогою цих функцій, коли вони шукають ключі зі значенням, яке є числом.

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

0

Тут вже багато відповідей, але я думаю, що я все-таки кину своє рішення на стек.

Ігровий майданчик 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>)

Для ясності:

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

Довідка для запису TypeScript

Приємна помічна функція:

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

// getAccountTypeName(AccountType.Twitter) === 'Twitter'

0

Щоб отримати список значень enum, який ви повинні використовувати:

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

Object.values(AnimalEnum);

-1

Це не зовсім відповідь на ваше запитання, але це хитрість вирішити вашу проблему.

export module Gender {

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

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

}

Ви можете розширити модель списку потрібним чином.

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

Тепер ви можете використовувати його таким чином:

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

або:

if(i === Gender.Type.Male){
  console.log("I am a man.");
}
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.