Sprawdź, czy wartość istnieje w wyliczeniu w TypeScript

163

Otrzymuję numer type = 3i muszę sprawdzić, czy istnieje w tym wyliczeniu:

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

Najlepszym sposobem, jaki znalazłem, jest pobranie wszystkich wartości wyliczenia jako tablicy i użycie na niej indexOf. Ale wynikowy kod nie jest zbyt czytelny:

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

Czy istnieje prostszy sposób na zrobienie tego?

Tim Schoch
źródło
if(Object.values(MESSAGE_TYPE).includes(+type)? Niewiele możesz zrobić.
Andrew Li
1
Działa to w ES6, ale niestety nie w ES5
Tim Schoch
@TimSchoch Możesz po prostu !!MESSAGE_TYPE[type]sprawdzić, czy istnieje wartość. MESSAGE_TYPE[type]zwróci wartość undefined, jeśli wartość typenie istnieje w dniuMESSAGE_TYPE
Kevin Babcock
1
@Kevin Babcock To jednak zakończy się niepowodzeniem w przypadku jednego z mapowań wartości wyliczenia 0.
Ingo Bürk,
@Ingo Bürk Świetna uwaga! Myślę, że można by dokonać wyraźnego sprawdzeniaMESSAGE_TYPE[type] !== undefined
Kevin Babcock

Odpowiedzi:

213

Jeśli chcesz, aby to działało z wyliczeniami ciągów, musisz użyć, Object.values(ENUM).includes(ENUM.value)ponieważ wyliczenia ciągów nie są odwrotnie mapowane, zgodnie z https://www.typescriptlang.org/docs/handbook/release-notes/typescript-2-4.html :

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

staje się:

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

Musisz więc tylko:

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

Jeśli pojawi się błąd dotyczący Property 'values' does not exist on type 'ObjectConstructor':, oznacza to, że nie kierujesz się na ES2017. Możesz użyć tej konfiguracji tsconfig.json:

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

Lub możesz po prostu wykonać dowolną obsadę:

if ((<any>Object).values(Vehicle).includes('car')) {
    // Do stuff here
}
Xiv
źródło
7
JSONLint jest wyświetlany Property 'values' does not exist on type 'ObjectConstructor'.
BBaysinger
5
@BBaysinger w maszynopisie spróbuj tego zamiast tego:(<any>Object).values(Vehicle).includes(Vehicle.car)
Salem Ouerdani,
1
Doskonały. To powinna być akceptowana odpowiedź. Zaakceptowana odpowiedź nie zadziała, jeśli moje klucze wyliczeniowe i wartości są różne
Pratap AK
2
To nie działa w maszynopisie. Również obejście zapewniło przerwy w IE
Jerin Joseph
3
Uważam, że to nie jest odpowiedź na to pytanie. Twoje rozwiązanie (Object.values(Vehicle).includes(Vehicle.car))zawsze będzie prawdziwe, ale pytanie brzmi, jak sprawdzić, czy dana wartość jest uwzględniona w wyliczeniu, na przykład (Object.values(Vehicle).includes('car'))powinna zwracać, trueale (Object.values(Vehicle).includes('plane'))powinna zwracać fałsz.
tommybernaciak
140

Jeśli używasz TypeScript, możesz użyć rzeczywistego wyliczenia . Następnie możesz to sprawdzić za pomocą in.

Działa to tylko wtedy, gdy wyliczenie jest oparte na liczbach i nie jest oznaczone const:

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

var type = 3;

if (type in MESSAGE_TYPE) {

}

Działa to, ponieważ kiedy kompilujesz powyższe wyliczenie, generuje on poniższy obiekt:

{
    '1': 'INFO',
    '2': 'SUCCESS',
    '3': 'WARNING',
    '4': 'ERROR',
    INFO: 1,
    SUCCESS: 2,
    WARNING: 3,
    ERROR: 4
}
Saravana
źródło
działa to tylko z odpowiednimi wyliczeniami, prawda? obecnie jest zdefiniowany jako:export const MESSAGE_TYPE = { ... }
Tim Schoch
Tak. Tylko z odpowiednimi wyliczeniami.
Saravana
ok, dzięki za wyjaśnienie. Sprawdzę, dlaczego nie używamy prawidłowego wyliczenia i zobaczę, czy możemy to zmienić.
Tim Schoch
MESSAGE_TYPEZgodnie z sugestią zmieniliśmy na rzeczywiste wyliczenie i teraz Twoje rozwiązanie działa jak urok. Dzięki @Saravana
Tim Schoch
71
To nie działa z wyliczeniami ciągów, ponieważ nie są one odwrotnie odwzorowane: 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
źródło
3
Najbardziej podoba mi się to
Ashley Coolman
3
W tym przykładzie użyto po prostu klucza == wartość i dlatego to działa, prawda? Jeśli klucz! = Wartość, będzie sprawdzane według klucza.
Konstantin Pelepelin
14
Właściwie ten przypadek działa tylko przez przypadek. „Wyliczenie1” zostałoby znalezione tylko dlatego, że ma taką samą wartość jak klucz. Ale jeśli klucze różnią się od wartości, to nie działa.
lukas_o
3
@lukas_o ma rację. To rozwiązanie na pierwszy rzut oka wygląda na przejrzyste, ale jest zdecydowanie podatne na błędy.
piotros
14

Na Twoje pytanie jest bardzo proste i łatwe rozwiązanie:

var districtId = 210;

if (DistrictsEnum[districtId] != null) {

// Returns 'undefined' if the districtId not exists in the DistrictsEnum 
    model.handlingDistrictId = districtId;
}
Ester Kaufman
źródło
Dziękuję Ester za odpowiedź. Odkąd przeszedłem od programowania do pełnoetatowego projektowania UX, nie mogę już tego zweryfikować. @crowd, daj mi znać, czy zaakceptowana odpowiedź jest nadal najlepsza w 2019! Pozdrawiam
Tim Schoch
2
@TimSchoch Mogę potwierdzić, że działa to bardzo dobrze, przynajmniej w przypadku wyliczeń numerycznych. To najbardziej eleganckie rozwiązanie imho.
Patrick P.
@PatrickP. czy możesz potwierdzić, że rozwiązanie zaproponowane przez firmę Ester działa również w przypadku wyliczeń łańcuchowych?
Tim Schoch
1
@TimSchoch Yes! Działa również w przypadku strun. jak słownik - możesz użyć dowolnego typu kluczy w słowniku.
Ester Kaufman
9
Należy zauważyć, że NIE działa to w przypadku wyliczeń ciągów, jeśli wyliczenie używa inicjatorów ciągów z innymi wartościami niż nazwy elementów członkowskich wyliczenia. Zobacz odpowiedź @ Xiv poniżej: stackoverflow.com/a/47755096/4752920
kcstricks
5
export enum UserLevel {
  Staff = 0,
  Leader,
  Manager,
}

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

Wynik różnicy w logu:

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

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

Rozwiązanie, musimy usunąć klucz jako liczbę.

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

Stosowanie

// 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
źródło