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.