Проверьте, существует ли значение в enum в TypeScript

163

Я получил номер type = 3и должен проверить, существует ли он в этом перечислении:

export const MESSAGE_TYPE = {
    INFO: 1,
    SUCCESS: 2,
    WARNING: 3,
    ERROR: 4,
};

Лучший способ, который я нашел, - это получить все значения Enum в виде массива и использовать для него indexOf. Но полученный код не очень разборчивый:

if( -1 < _.values( MESSAGE_TYPE ).indexOf( _.toInteger( type ) ) ) {
    // do stuff ...
}

Есть ли более простой способ сделать это?

Тим Шох
источник
if(Object.values(MESSAGE_TYPE).includes(+type)? Там не так много, вы можете сделать.
Эндрю Ли
1
Это работает в ES6, но не в ES5, к сожалению
Тим Шох
@TimSchoch Вы можете просто !!MESSAGE_TYPE[type]проверить, существует ли значение. MESSAGE_TYPE[type]вернет undefined, если значение typeне существует наMESSAGE_TYPE
Кевин Бэбкок
1
@Kevin Babcock Это потерпит неудачу 0, хотя одно из значений enum сопоставляется .
Инго Бюрк,
@ Инго Бюрк Отличный момент! Я предполагаю, что можно сделать явную проверкуMESSAGE_TYPE[type] !== undefined
Кевин Бэбкок,

Ответы:

213

Если вы хотите, чтобы это работало со строковыми перечислениями, вам нужно использовать это, Object.values(ENUM).includes(ENUM.value)потому что строковые перечисления не отображаются в обратном порядке, согласно https://www.typescriptlang.org/docs/handbook/release-notes/typescript-2-4.html :

Enum Vehicle {
    Car = 'car',
    Bike = 'bike',
    Truck = 'truck'
}

будет выглядеть так:

{
    Car: 'car',
    Bike: 'bike',
    Truck: 'truck'
}

Так что вам просто нужно сделать:

if (Object.values(Vehicle).includes('car')) {
    // Do stuff here
}

Если вы получили сообщение об ошибке:, Property 'values' does not exist on type 'ObjectConstructor'значит, вы не ориентируетесь на ES2017. Вы можете использовать эту конфигурацию tsconfig.json:

"compilerOptions": {
    "lib": ["es2017"]
}

Или вы можете просто сделать любой актерский состав:

if ((<any>Object).values(Vehicle).includes('car')) {
    // Do stuff here
}
Xiv
источник
7
JSONLint показывает Property 'values' does not exist on type 'ObjectConstructor'.
BBaysinger
5
@Baysbinger в машинописном тексте попробуйте это вместо этого:(<any>Object).values(Vehicle).includes(Vehicle.car)
Салем Уердани
1
Превосходно. Это должен быть принятый ответ. Принятый ответ не сработает, если мои enum-ключи и значения отличаются
Pratap AK
2
Это не работает в машинописи. Также работа вокруг обеспечила перерывы в IE
Джерин Джозеф
3
Я считаю, что это не ответ на этот вопрос. Ваше решение (Object.values(Vehicle).includes(Vehicle.car))всегда будет верным, но вопрос в том, как проверить, что заданное значение включено в enum, например, (Object.values(Vehicle).includes('car'))должно возвращаться, trueно (Object.values(Vehicle).includes('plane'))должно возвращать false.
Томмибернакиак
140

Если вы используете TypeScript, вы можете использовать фактическое перечисление . Тогда вы можете проверить это с помощью in.

Это работает, только если ваше перечисление основано на числе и не помечено const:

export enum MESSAGE_TYPE {
    INFO = 1,
    SUCCESS = 2,
    WARNING = 3,
    ERROR = 4,
};

var type = 3;

if (type in MESSAGE_TYPE) {

}

Это работает, потому что, когда вы компилируете перечисленное выше перечисление, оно генерирует следующий объект:

{
    '1': 'INFO',
    '2': 'SUCCESS',
    '3': 'WARNING',
    '4': 'ERROR',
    INFO: 1,
    SUCCESS: 2,
    WARNING: 3,
    ERROR: 4
}
Saravana
источник
это работает только с правильными перечислениями, верно? в настоящее время это определяется так:export const MESSAGE_TYPE = { ... }
Тим Шох
Да. Только с правильными перечислениями.
Саравана
хорошо, спасибо за объяснение. Я проверю, почему мы не используем правильное перечисление, и посмотрю, сможем ли мы его изменить.
Тим
Мы изменили MESSAGE_TYPEна фактическое перечисление, как вы предложили, и теперь ваше решение работает как шарм. Спасибо @Saravana
Тим Шох
71
Это не работает со строковыми перечислений , так как они не отображаются обратное: typescriptlang.org/docs/handbook/release-notes/...
Xiv
20

TypeScript v3.7.3

export enum YourEnum {
   enum1 = 'enum1',
   enum2 = 'enum2',
   enum3 = 'enum3',
}

const status = 'enumnumnum';

if (!(status in YourEnum)) {
     throw new UnprocessableEntityResponse('Invalid enum val');
}
Джейсон С.А.
источник
3
Мне это нравится больше всего
Эшли Кулман
3
Так что этот пример просто использует ключ == значение, и это причина, по которой он работает, верно? Если ключ! = Значение, он будет проверяться по ключу.
Константин Пелепелин
14
На самом деле этот случай работает только из-за совпадения. 'enum1' будет найден только потому, что это то же значение, что и ключ. Но если ключи отличаются от значений, это не работает.
lukas_o
3
@lukas_o прав в этом. На первый взгляд, это решение выглядит прозрачным, но оно определенно подвержено ошибкам.
пиотрос
14

Существует очень простое и легкое решение вашего вопроса:

var districtId = 210;

if (DistrictsEnum[districtId] != null) {

// Returns 'undefined' if the districtId not exists in the DistrictsEnum 
    model.handlingDistrictId = districtId;
}
Эстер Кауфман
источник
Спасибо, Эстер, за твой ответ. Так как я перешел от программирования к UX Design с полной занятостью, я больше не могу это проверить. @ толпа, дайте мне знать, если я все еще вернусь к ответу в 2019 году! Приветствия
Тим Шох
2
@TimSchoch Я могу подтвердить, что это работает очень хорошо, по крайней мере для числовых перечислений. Это самое элегантное решение imho.
Патрик П.
@PatrickP. Вы можете подтвердить, что решение, предложенное Эстер, работает и для строковых перечислений?
Тим
1
@ ТимШок Да! Это работает для строк тоже. как словарь - вы можете использовать любой тип для ключей в словаре.
Эстер Кауфман
9
Обратите внимание, что это НЕ работает для строковых перечислений, если перечисление использует строковые инициализаторы с значениями, отличными от имен членов перечисления. См. Ответ @ Xiv ниже: stackoverflow.com/a/47755096/4752920
kcstricks
5
export enum UserLevel {
  Staff = 0,
  Leader,
  Manager,
}

export enum Gender {
  None = "none",
  Male = "male",
  Female = "female",
}

Разница результата в журнале:

log(Object.keys(Gender))
=>
[ 'None', 'Male', 'Female' ]

log(Object.keys(UserLevel))
=>
[ '0', '1', '2', 'Staff', 'Leader', 'Manager' ]

Решение, нам нужно удалить ключ в виде числа.

export class Util {
  static existValueInEnum(type: any, value: any): boolean {
    return Object.keys(type).filter(k => isNaN(Number(k))).filter(k => type[k] === value).length > 0;
  }
}

использование

// For string value
if (!Util.existValueInEnum(Gender, "XYZ")) {
  //todo
}

//For number value, remember cast to Number using Number(val)
if (!Util.existValueInEnum(UserLevel, 0)) {
  //todo
}
Нхан Цао
источник
0

Согласно ответу Райана Кавано , вы можете просто сделать следующее, чтобы проверить, содержится ли значение в данном перечислении:

if ('value4' in someEnum) {
  // ...
}
А. Мэтр
источник