Vérifier si la valeur existe dans enum dans TypeScript

163

Je reçois un numéro type = 3et je dois vérifier s'il existe dans cette énumération:

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

Le meilleur moyen que j'ai trouvé est d'obtenir toutes les valeurs Enum sous forme de tableau et d'utiliser indexOf dessus. Mais le code résultant n'est pas très lisible:

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

Existe-t-il un moyen plus simple de procéder?

Tim Schoch
la source
if(Object.values(MESSAGE_TYPE).includes(+type)? Vous ne pouvez pas faire grand-chose.
Andrew Li
1
Cela fonctionne dans ES6 mais pas dans ES5 malheureusement
Tim Schoch
@TimSchoch Vous pouvez simplement !!MESSAGE_TYPE[type]vérifier si une valeur existe. MESSAGE_TYPE[type]renverra undefined si la valeur de typen'existe pas surMESSAGE_TYPE
Kevin Babcock
1
@Kevin Babcock Cela échouera avec l'une des valeurs d'énumération mappées à 0.
Ingo Bürk
@Ingo Bürk Excellent point! Je suppose qu'une vérification explicite pourrait être faiteMESSAGE_TYPE[type] !== undefined
Kevin Babcock

Réponses:

213

Si vous voulez que cela fonctionne avec les énumérations de chaînes, vous devez l'utiliser Object.values(ENUM).includes(ENUM.value)car les énumérations de chaînes ne sont pas inversées, selon https://www.typescriptlang.org/docs/handbook/release-notes/typescript-2-4.html :

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

devient:

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

Il vous suffit donc de faire:

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

Si vous obtenez une erreur pour Property 'values' does not exist on type 'ObjectConstructor':, vous ne ciblez pas ES2017. Vous pouvez soit utiliser cette configuration tsconfig.json:

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

Ou vous pouvez simplement faire un casting:

if ((<any>Object).values(Vehicle).includes('car')) {
    // Do stuff here
}
Xiv
la source
7
JSONLint s'affiche Property 'values' does not exist on type 'ObjectConstructor'.
BBaysinger
5
@BBaysinger en écriture manuscrite, essayez plutôt ceci:(<any>Object).values(Vehicle).includes(Vehicle.car)
Salem Ouerdani
1
Excellent. Cela devrait être la réponse acceptée. La réponse acceptée ne fonctionnera pas si mes clés d'énumération et mes valeurs sont différentes
Pratap AK
2
Cela ne fonctionne pas en tapuscrit. Aussi le travail autour a fourni des pauses dans IE
Jerin Joseph
3
Je pense que ce n’est pas une réponse à cette question. Votre solution (Object.values(Vehicle).includes(Vehicle.car))sera toujours vraie, mais la question est de savoir comment vérifier qu'une valeur donnée est incluse dans enum, par exemple (Object.values(Vehicle).includes('car'))doit renvoyer truemais (Object.values(Vehicle).includes('plane'))doit renvoyer false.
tommybernaciak
140

Si vous utilisez TypeScript, vous pouvez utiliser une énumération réelle . Ensuite, vous pouvez le vérifier en utilisant in.

Cela ne fonctionne que si votre énumération est basée sur des nombres et non marquée const:

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

var type = 3;

if (type in MESSAGE_TYPE) {

}

Cela fonctionne car lorsque vous compilez l'énumération ci-dessus, cela génère l'objet ci-dessous:

{
    '1': 'INFO',
    '2': 'SUCCESS',
    '3': 'WARNING',
    '4': 'ERROR',
    INFO: 1,
    SUCCESS: 2,
    WARNING: 3,
    ERROR: 4
}
Saravana
la source
cela ne fonctionne qu'avec des énumérations appropriées, non? actuellement, il est défini comme tel:export const MESSAGE_TYPE = { ... }
Tim Schoch
Oui. Seulement avec des énumérations appropriées.
Saravana
ok, merci pour l'explication. Je vais vérifier pourquoi nous n'utilisons pas une énumération correcte et voir si nous pouvons la changer.
Tim Schoch
Nous avons changé MESSAGE_TYPEpour une énumération réelle comme vous l'avez suggéré et maintenant votre solution fonctionne comme un charme. Merci @Saravana
Tim Schoch
71
Cela ne fonctionne pas avec les énumérations de chaînes car elles ne sont pas inversées: typescriptlang.org/docs/handbook/release-notes/...
Xiv
19

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
la source
3
J'aime ça le plus
Ashley Coolman
3
Donc, cet exemple utilise simplement la clé == valeur et c'est la raison pour laquelle cela fonctionne, non? Si clé! = Valeur, il vérifierait par clé.
Konstantin Pelepelin
14
En fait, ce cas ne fonctionne que par coïncidence. 'enum1' ne serait trouvé que parce que c'est la même valeur que la clé. Mais si les clés diffèrent des valeurs, cela ne fonctionne pas.
lukas_o
3
@lukas_o a raison à ce sujet. Cette solution semble claire à première vue, mais elle est certainement sujette aux bogues.
piotros le
14

Il existe une solution très simple et facile à votre question:

var districtId = 210;

if (DistrictsEnum[districtId] != null) {

// Returns 'undefined' if the districtId not exists in the DistrictsEnum 
    model.handlingDistrictId = districtId;
}
Ester Kaufman
la source
Merci Ester pour votre réponse. Depuis que je suis passé de la programmation à la conception UX à plein temps, je ne peux plus le vérifier. @crowd, faites-moi savoir si la réponse acceptée est toujours la voie à suivre en 2019! Cheers
Tim Schoch
2
@TimSchoch Je peux confirmer que cela fonctionne très bien au moins pour les énumérations numériques. C'est la solution la plus élégante à mon avis.
Patrick P.
@PatrickP. pouvez-vous confirmer que la solution proposée par Ester fonctionne aussi pour les énumérations de chaînes?
Tim Schoch
1
@TimSchoch Oui! Cela fonctionne aussi pour les chaînes. comme un dictionnaire - vous pouvez utiliser n'importe quel type pour les clés du dictionnaire.
Ester Kaufman le
9
Notez que cela ne fonctionne PAS pour les énumérations de chaînes si l'énumération utilise des initialiseurs de chaîne avec des valeurs différentes de celles des noms de membres d'énumération. Voir la réponse de @ Xiv ci-dessous: stackoverflow.com/a/47755096/4752920
kcstricks
5
export enum UserLevel {
  Staff = 0,
  Leader,
  Manager,
}

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

Résultat de la différence dans le journal:

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

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

La solution, nous devons supprimer la clé en tant que nombre.

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

Usage

// 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
la source
0

Selon la réponse de Ryan Cavanaugh , vous pouvez simplement faire ce qui suit pour vérifier si une valeur est contenue dans une énumération donnée:

if ('value4' in someEnum) {
  // ...
}
A. Maître
la source