TypeScript'te numaralandırmada değerin var olup olmadığını kontrol edin


182

Bir numara alıyorum type = 3ve bu numaralandırmada var olup olmadığını kontrol etmem gerekiyor:

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

Bulduğum en iyi yol, tüm Enum Değerlerini bir dizi olarak alıp üzerinde indexOf kullanmaktır. Ancak ortaya çıkan kod çok okunaklı değil:

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

Bunu yapmanın daha basit bir yolu var mı?


if(Object.values(MESSAGE_TYPE).includes(+type)? Yapabileceğin pek bir şey yok.
Andrew Li

1
Bu ES6'da çalışıyor ama ES5'te maalesef çalışmıyor
Tim Schoch

@TimSchoch !!MESSAGE_TYPE[type]Bir değerin var olup olmadığını kontrol etmek için yapabilirsiniz . MESSAGE_TYPE[type]değeri tarihinde typeyoksa tanımsız olarak dönecektirMESSAGE_TYPE
Kevin Babcock

1
@Kevin Babcock Yine de enum değerlerinden biri başarısız olur 0.
Ingo Bürk

@Ingo Bürk Harika nokta! Sanırım açık bir kontrol yapılabilirMESSAGE_TYPE[type] !== undefined
Kevin Babcock

Yanıtlar:


244

Bunun dize numaralandırmalarıyla çalışmasını istiyorsanız Object.values(ENUM).includes(ENUM.value), https://www.typescriptlang.org/docs/handbook/release-notes/typescript-2-4.html'ye göre dize numaralandırmaları ters eşlenmediği için kullanmanız gerekir :

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

şu hale gelir:

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

Yani yapmanız gereken tek şey:

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

Property 'values' does not exist on type 'ObjectConstructor'Şunun için bir hata alırsanız: ES2017'yi hedeflemiyorsunuz demektir. Ya bu tsconfig.json yapılandırmasını kullanabilirsiniz:

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

Veya herhangi bir oyuncu kadrosunu yapabilirsiniz:

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

8
JSONLint gösteriyor Property 'values' does not exist on type 'ObjectConstructor'.
BBaysinger

5
Yazı tipindeki @BBaysinger bunun yerine şunu deneyin:(<any>Object).values(Vehicle).includes(Vehicle.car)
Salem Ouerdani

3
Bu, typcript'te çalışmaz. Ayrıca IE'de molalar sağladı
Jerin Joseph

3
Bunun bu sorunun cevabı olmadığına inanıyorum. Çözümünüz (Object.values(Vehicle).includes(Vehicle.car))her zaman doğru olacaktır, ancak soru, belirli bir değerin enum'a dahil (Object.values(Vehicle).includes('car'))edilip edilmediğinin nasıl kontrol edileceğidir, örneğin dönmesi, trueancak (Object.values(Vehicle).includes('plane'))yanlış döndürmesi gerekir.
tommybernaciak

9
Object.values(Vehicle).includes('car')ancak uyarır, Argument of type 'string' is not assignable to parameter of type 'Vehicle'bu nedenle ayrıca assert yazmanız gerekir
JHH,

155

Bu yalnızca sabit olmayan, sayı tabanlı numaralandırmalar üzerinde çalışır. Diğer türlerin sabit numaralandırmaları veya numaralandırmaları için yukarıdaki cevaba bakın


TypeScript kullanıyorsanız, gerçek bir enum kullanabilirsiniz . Daha sonra kullanarak kontrol edebilirsiniz in.

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

var type = 3;

if (type in MESSAGE_TYPE) {

}

Bu çalışır çünkü yukarıdaki numaralandırmayı derlediğinizde aşağıdaki nesneyi oluşturur:

{
    '1': 'INFO',
    '2': 'SUCCESS',
    '3': 'WARNING',
    '4': 'ERROR',
    INFO: 1,
    SUCCESS: 2,
    WARNING: 3,
    ERROR: 4
}

bu yalnızca uygun numaralandırmalarla çalışır, değil mi? şu anda şu şekilde tanımlanmıştır:export const MESSAGE_TYPE = { ... }
Tim Schoch

Evet. Yalnızca uygun numaralandırmalarla.
Saravana

tamam, açıklama için teşekkürler. Neden uygun bir enum kullanmadığımızı kontrol edeceğim ve bunu değiştirip değiştiremeyeceğimize bakacağım.
Tim Schoch

MESSAGE_TYPEÖnerdiğiniz gibi gerçek bir numaralandırmaya geçtik ve şimdi çözümünüz bir cazibe gibi çalışıyor. Teşekkürler @Saravana
Tim Schoch

80
Bu, ters eşlenmemiş oldukları için dize numaralandırmalarıyla çalışmaz: typescriptlang.org/docs/handbook/release-notes/…
Xiv

25

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
Bunu en çok beğendim
Ashley Coolman

3
Yani bu örnek sadece anahtar == değer kullanıyor ve çalışmasının nedeni bu, değil mi? Anahtar! = Değer ise, anahtarla kontrol eder.
Konstantin Pelepelin

30
Aslında bu dava sadece bir tesadüf yüzünden işler. "enum1" yalnızca anahtarla aynı değerde olduğu için bulunur. Ancak anahtarlar değerlerden farklıysa çalışmaz.
lukas_o

5
@lukas_o bu konuda haklı. Bu çözüm ilk bakışta net görünüyor ancak kesinlikle hataya açık.
piotros

16

Sorunuzun çok basit ve kolay bir çözümü var:

var districtId = 210;

if (DistrictsEnum[districtId] != null) {

// Returns 'undefined' if the districtId not exists in the DistrictsEnum 
    model.handlingDistrictId = districtId;
}

Cevabınız için teşekkürler Ester. Programlamadan tam zamanlı UX Tasarımına geçtiğim için artık bunu doğrulayamıyorum. @crowd, kabul edilen cevabın 2019'da hala gidilecek yol olup olmadığını bana bildirin! Şerefe
Tim Schoch

2
@TimSchoch Bunun en azından sayısal numaralandırmalar için çok iyi çalıştığını doğrulayabilirim. Bu, en zarif çözüm imho.
Patrick P.

@PatrickP. Ester tarafından önerilen çözümün dizi numaralandırmaları için de çalıştığını doğrulayabilir misiniz?
Tim Schoch

1
@TimSchoch Evet! Dizeler için de işe yarar. Sözlük gibi - sözlükteki tuşlar için herhangi bir türü kullanabilirsiniz.
Ester Kaufman

13
Enum, enum üye adlarından farklı değerlere sahip dize başlatıcıları kullanıyorsa, bunun dize numaralandırmaları için çalışmadığını unutmayın. @
Xiv'in

7
export enum UserLevel {
  Staff = 0,
  Leader,
  Manager,
}

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

Günlükte fark sonucu:

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

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

Çözüm, anahtarı sayı olarak kaldırmamız gerekiyor.

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

Kullanım

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

5

Sandersn'e göre bunu yapmanın en iyi yolu şudur :

Object.values(MESSAGE_TYPE).includes(type as MESSAGE_TYPE)

Bu muhtemelen en iyi ve en güvenli cevaptır. Kullanımından kaçınır any. type in MESSAGE_TYPEBunu bir anahtar arama yerine bir değer arama beri anahtar ve enum değeri aynı olacağını garanti edemez eğer sözdizimi daha iyi olabilir.
rpivovar

1

Buraya gelip bir dizenin bir numaralandırmanın değerlerinden biri olup olmadığını doğrulamak isteyen ve onu dönüştüren tür için, uygun türü döndüren undefinedve dize enum'da değilse dönen bu işlevi yazdım .

function keepIfInEnum<T>(
  value: string,
  enumObject: { [key: string]: T }
) {
  if (Object.values(enumObject).includes((value as unknown) as T)) {
    return (value as unknown) as T;
  } else {
    return undefined;
  }
}

Örnek olarak:

enum StringEnum {
  value1 = 'FirstValue',
  value2 = 'SecondValue',
}
keepIfInEnum<StringEnum>('FirstValue', StringEnum)  // 'FirstValue'
keepIfInEnum<StringEnum>('OtherValue', StringEnum)  // undefined

0
enum ServicePlatform {
    UPLAY = "uplay",
    PSN = "psn",
    XBL = "xbl"
}

şu hale gelir:

{ UPLAY: 'uplay', PSN: 'psn', XBL: 'xbl' }

yani

ServicePlatform.UPLAY in ServicePlatform // false

ÇÖZÜM:

ServicePlatform.UPLAY.toUpperCase() in ServicePlatform // true
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.