检查TypeScript中枚举中是否存在值

时间:2017-05-05 12:20:25

标签: javascript typescript enums

我收到一个数字type = 3并且必须检查它是否存在于此枚举中:

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

我发现的最好方法是将所有枚举值作为数组并使用indexOf。但结果代码不太清晰:

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

有更简单的方法吗?

12 个答案:

答案 0 :(得分:85)

如果您使用的是TypeScript,则可以使用actual enum。然后,您可以使用in进行检查。请注意,仅当您的枚举不是const且基于数字时才有效:

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

var type = 3;

if (type in MESSAGE_TYPE) {

}

这是有效的,因为在编译上面的枚举时,它会生成以下对象:

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

答案 1 :(得分:78)

如果您希望使用字符串枚举,则需要使用Object.values(ENUM).includes(ENUM.value),因为根据https://www.typescriptlang.org/docs/handbook/release-notes/typescript-2-4.html,字符串枚举不会反向映射:

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

变为:

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

所以你只需要这样做:

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

如果您收到错误:Property 'values' does not exist on type 'ObjectConstructor',那么您的目标不是ES2017。您可以使用此tsconfig.json配置:

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

或者你可以做任何演员:

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

答案 2 :(得分: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 :(得分:8)

According to sandersn的最佳方法是:

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

答案 4 :(得分:6)

有一个非常简单的解决方案可以解决您的问题:

var districtId = 210;

if (DistrictsEnum[districtId] != null) {

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

答案 5 :(得分:6)

类型断言是不可避免的。关注

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

我找到了一个没有提到的替代方案,所以我想分享一下我的修复方法:

const someString: Vehicle | string = 'car';
const inEnum = (Object.values(Vehicle) as string[]).includes(someString);

我觉得这更真实,因为我们通常使用类型安全(带有字符串)并希望将其与枚举进行比较;将其类型转换为 any(原因:永远不要这样做)或 Vehicle(原因:可能不真实)有点鲁莽。相反,将 Object.values() 输出类型转换为字符串数组实际上非常真实。

答案 6 :(得分:2)

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

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

日志中的差异结果:

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

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

解决方案,我们需要删除密钥作为数字。

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

用法

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

答案 7 :(得分:2)

更新:

我发现,每当我需要检查枚举中是否存在某个值时,我实际上并不需要枚举,而类型是更好的解决方案。所以我的原始答案中的枚举变为:

export type ValidColors =
  | "red"
  | "orange"
  | "yellow"
  | "green"
  | "blue"
  | "purple";

原答案:

为了清楚起见,我喜欢将 valuesincludes 调用分成单独的行。举个例子:

export enum ValidColors {
  Red = "red",
  Orange = "orange",
  Yellow = "yellow",
  Green = "green",
  Blue = "blue",
  Purple = "purple",
}

function isValidColor(color: string): boolean {
  const options: string[] = Object.values(ValidColors);
  return options.includes(color);
}

答案 8 :(得分:1)

对于来这里验证字符串是否为枚举值之一并进行类型转换的任何人,我编写了此函数,该函数返回正确的类型,如果字符串不在字符串中,则返回undefined枚举。

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

例如:

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

答案 9 :(得分:0)

如果您在那里找到如何检查联合包含特定值的方法,则有解决方案:

// source enum type
export const EMessagaType = {
   Info,
   Success,
   Warning,
   Error,
};

//check helper
const isUnionHasValue = <T extends number>(union: T, value: T) =>
   (union & value) === value;


//tests
console.log(
 isUnionHasValue(EMessagaType.Info | EMessagaType.Success), 
 EMessagaType.Success);

//output: true


console.log(
 isUnionHasValue(EMessagaType.Info | EMessagaType.Success), 
 EMessagaType.Error); 

//output: false

答案 10 :(得分:0)

以下函数返回另一个函数,该函数充当输入枚举的类型谓词(假设它是字符串样式的枚举)。

function constructEnumPredicate<RuntimeT extends string, EnumClass extends {[key: string]: RuntimeT}>(enumClass: EnumClass): (maybeEnum: string) => maybeEnum is EnumClass[keyof EnumClass] {
    const reverseMapping: {[key: string]: boolean} = {};

    for (const enumVal in enumClass) {
        const enumStr = enumClass[enumVal];
        reverseMapping[enumStr] = true;
    }

    function result(maybeEnum: any): maybeEnum is EnumClass[keyof EnumClass] {
        return !!reverseMapping[maybeEnum];
    }

    return result;
}

它适用于 TypeScript 4.2.4,但我没有测试过早期版本。

主要有趣的部分是 EnumClass[keyof EnumClass] 返回类型。当这样的类型是 TypeScript 中的枚举时,它返回枚举的原始类型,其中 EnumClass 是运行时枚举类的类型。

关于如何使用这种结构的示例,假设我们有以下枚举:

enum Direction {
    Left = "<-",
    Right = "->"
}

Direction 既是类型也是运行时对象。我们可以为 Direction 生成一个类型谓词并像这样使用它:

const isDirection = constructEnumPredicate(Direction);
function coerceDirection(maybeDir: string): Direction {
    // Since we make a type predicate rather than just a normal predicate,
    // no explicit type casting is necessary!
    return isDirection(maybeDir) ? maybeDir : Direction.Left;
}

答案 11 :(得分:-2)

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

成为:

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

如此

ServicePlatform.UPLAY in ServicePlatform // false

解决方案:

ServicePlatform.UPLAY.toUpperCase() in ServicePlatform // true