Verifique se o valor existe na enumeração no TypeScript

163

Eu recebo um número type = 3e tenho que verificar se ele existe nesta enumeração:

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

A melhor maneira que eu encontrei é obtendo todos os valores de enum como uma matriz e usando indexOf nela. Mas o código resultante não é muito legível:

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

Existe uma maneira mais simples de fazer isso?

Tim Schoch
fonte
if(Object.values(MESSAGE_TYPE).includes(+type)? Não há muito que você possa fazer.
Andrew Li
1
Isso funciona em ES6, mas não em ES5 infelizmente
Tim Schoch
@ TimSchoch Você pode fazer isso apenas !!MESSAGE_TYPE[type]para verificar se existe um valor. MESSAGE_TYPE[type]irá retornar undefined se o valor typenão existir noMESSAGE_TYPE
Kevin Babcock
1
@ Kevin Babcock Isso irá falhar em um dos valores de enumeração para 0, no entanto.
Ingo Bürk
@Ingo Bürk Ótimo ponto! Eu acho que uma verificação explícita poderia ser feitoMESSAGE_TYPE[type] !== undefined
Kevin Babcock

Respostas:

211

Se você deseja que isso funcione com enumerações de strings, é necessário usá- Object.values(ENUM).includes(ENUM.value)las porque as enumerações de string não são mapeadas inversamente, de acordo com https://www.typescriptlang.org/docs/handbook/release-notes/typescript-2-4.html :

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

torna-se:

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

Então você só precisa fazer:

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

Se você receber um erro para Property 'values' does not exist on type 'ObjectConstructor':, não estará direcionando o ES2017. Você pode usar esta configuração do tsconfig.json:

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

Ou você pode simplesmente fazer um elenco:

if ((<any>Object).values(Vehicle).includes('car')) {
    // Do stuff here
}
Xiv
fonte
7
JSONLint está sendo exibido Property 'values' does not exist on type 'ObjectConstructor'.
BBaysinger
5
@BBaysinger à máquina tentar isso em vez disso:(<any>Object).values(Vehicle).includes(Vehicle.car)
Salem Ouerdani
1
Excelente. Essa deve ser a resposta aceita. Resposta aceita não funcionará se as chaves do meu enum e os valores são diferentes
Pratap AK
2
Isso não funciona em texto datilografado. Também o trabalho em torno das interrupções fornecidas no IE
Jerin Joseph
3
Eu acredito que isso não é uma resposta para esta pergunta. Sua solução (Object.values(Vehicle).includes(Vehicle.car))sempre será verdadeira, mas a questão é como verificar se um determinado valor está incluído no enum, por exemplo, (Object.values(Vehicle).includes('car'))deve retornar, truemas (Object.values(Vehicle).includes('plane'))deve retornar false.
tommybernaciak
140

Se você estiver usando o TypeScript, poderá usar uma enumeração real . Então você pode verificar usando in.

Isso funciona apenas se sua enumeração for baseada em número e não marcada const:

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

var type = 3;

if (type in MESSAGE_TYPE) {

}

Isso funciona porque quando você compila a enumeração acima, ela gera o objeto abaixo:

{
    '1': 'INFO',
    '2': 'SUCCESS',
    '3': 'WARNING',
    '4': 'ERROR',
    INFO: 1,
    SUCCESS: 2,
    WARNING: 3,
    ERROR: 4
}
Saravana
fonte
isso só funciona com enums apropriadas, certo? atualmente está definido como tal:export const MESSAGE_TYPE = { ... }
Tim Schoch
Sim. Somente com enums apropriados.
Saravana
ok, obrigado pela explicação. Vou verificar por que não estamos usando uma enumeração adequada e ver se podemos alterá-la.
Tim Schoch
Alteramos MESSAGE_TYPEpara uma enumeração real, como você sugeriu, e agora sua solução funciona como um encanto. Obrigado @Saravana
Tim Schoch
71
Isso não funciona com enumerações de strings, porque elas não são mapeadas ao contrário: 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');
}
Jayson SA
fonte
3
Eu gosto mais disso
Ashley Coolman 06/02
3
Portanto, este exemplo está apenas usando key == value e é por isso que funciona, certo? Se chave! = Valor, seria verificado por chave.
Konstantin Pelepelin
13
Na verdade, este caso funciona apenas por causa de uma coincidência. 'enum1' seria encontrado apenas porque é o mesmo valor da chave. Mas se as chaves diferem dos valores, não funciona.
lukas_o 20/04
3
@lukas_o está certo sobre isso. Esta solução parece clara à primeira vista, mas definitivamente está sujeita a erros.
piotros
14

Existe uma solução muito simples e fácil para sua pergunta:

var districtId = 210;

if (DistrictsEnum[districtId] != null) {

// Returns 'undefined' if the districtId not exists in the DistrictsEnum 
    model.handlingDistrictId = districtId;
}
Ester Kaufman
fonte
Obrigado Ester pela sua resposta. Desde que mudei da programação para o UX Design em período integral, não posso mais verificar isso. @crowd, deixe-me saber se a resposta aceita ainda é o caminho a seguir em 2019! Cheers
Tim Schoch
2
@ TimSchoch Posso confirmar que isso funciona muito bem, pelo menos para enumerações numéricas. Esta é a solução mais elegante imho.
Patrick P.
@PatrickP. você pode confirmar que a solução proposta por Ester também funciona para enumerações de strings?
21719 Tim
1
@TimSchoch Yes! Também funciona para strings. como um dicionário - você pode usar qualquer tipo para as chaves no dicionário.
Ester Kaufman
9
Observe que isso NÃO funciona para enumerações de strings se o enum usar inicializadores de strings com valores diferentes dos nomes dos membros do enum. Veja a resposta do @ Xiv abaixo: stackoverflow.com/a/47755096/4752920
kcstricks
5
export enum UserLevel {
  Staff = 0,
  Leader,
  Manager,
}

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

Resultado da diferença no log:

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

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

A solução, precisamos remover a chave como um número.

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

Uso

// 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
}
Nhan Cao
fonte