515

I receive a number type = 3 and have to check if it exists in this enum:

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

The best way I found is by getting all Enum Values as an array and using indexOf on it. But the resulting code isn't very legible:

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

Is there a simpler way of doing this?

6
  • 3
    if(Object.values(MESSAGE_TYPE).includes(+type)? There's not much you can do.
    – Andrew Li
    Commented May 5, 2017 at 12:26
  • 1
    This works in ES6 but not in ES5 unfortunately
    – Tim Schoch
    Commented May 5, 2017 at 12:36
  • @TimSchoch You can just do !!MESSAGE_TYPE[type]to check if a value exists. MESSAGE_TYPE[type] will return undefined if the value of type doesn't exist on MESSAGE_TYPE Commented Sep 26, 2018 at 21:57
  • 2
    @Kevin Babcock That will fail of one of the enum values maps to 0, though.
    – Ingo Bürk
    Commented Sep 29, 2018 at 8:50
  • @Ingo Bürk Great point! I guess an explicit check could be made MESSAGE_TYPE[type] !== undefined Commented Oct 3, 2018 at 18:59

14 Answers 14

649

If you want this to work with string enums, you need to use Object.values(ENUM).includes(ENUM.value) because string enums are not reverse mapped, according to https://www.typescriptlang.org/docs/handbook/release-notes/typescript-2-4.html#string-enums:

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

becomes:

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

So you just need to do:

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

If you get an error for: Property 'values' does not exist on type 'ObjectConstructor', then you are not targeting ES2017. You can either use this tsconfig.json config:

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

Or you can just do an any cast:

if ((<any>Object).values(Vehicle).includes('car')) {
    // Do stuff here
}
21
  • 18
    JSONLint is showing Property 'values' does not exist on type 'ObjectConstructor'.
    – BBaysinger
    Commented Feb 13, 2018 at 4:09
  • 5
    @BBaysinger in typescript try this instead: (<any>Object).values(Vehicle).includes(Vehicle.car) Commented Feb 27, 2018 at 5:11
  • 10
    I believe that this is not an answer to this question. Your solution (Object.values(Vehicle).includes(Vehicle.car)) will always be true, but the question is how check that a given value is included in enum, for example (Object.values(Vehicle).includes('car')) should return true but (Object.values(Vehicle).includes('plane')) should return false. Commented Feb 10, 2020 at 13:55
  • 94
    Object.values(Vehicle).includes('car') however warns Argument of type 'string' is not assignable to parameter of type 'Vehicle' so you also have to type assert
    – JHH
    Commented May 14, 2020 at 9:03
  • 97
    Object.values<string>(Enum).includes(value) works for me
    – m.rufca
    Commented May 6, 2021 at 16:07
355

This works only on non-const, number-based enums. For const enums or enums of other types, see this answer


If you are using TypeScript, you can use an actual enum. Then you can check it using in.

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

var type = 3;

if (type in MESSAGE_TYPE) {

}

This works because when you compile the above enum, it generates the below object:

{
    '1': 'INFO',
    '2': 'SUCCESS',
    '3': 'WARNING',
    '4': 'ERROR',
    INFO: 1,
    SUCCESS: 2,
    WARNING: 3,
    ERROR: 4
}
10
  • 1
    this only works with proper enums, right? currently it is defined as such: export const MESSAGE_TYPE = { ... }
    – Tim Schoch
    Commented May 5, 2017 at 12:41
  • 2
    Yes. Only with proper enums.
    – Saravana
    Commented May 5, 2017 at 12:42
  • 163
    This does not work with string enums because they are not reverse mapped: typescriptlang.org/docs/handbook/release-notes/…
    – Xiv
    Commented Dec 11, 2017 at 14:26
  • 13
    It seems like this approach works with string enums in 2021.
    – Gus
    Commented Jun 28, 2021 at 21:35
  • 2
    For string enums it only works if your enum keys are the same as values, e.g. enum Enum { foo = 'foo' }; But I wouldn't recommend relying on it in this case
    – grumd
    Commented Jul 24, 2022 at 10:24
153

According to sandersn the best way to do this would be:

Object.values(MESSAGE_TYPE).includes(type as MESSAGE_TYPE)
9
  • 3
    This is probably the best and safest answer. It avoids the use of any. The type in MESSAGE_TYPE syntax might be better if you can guarantee that the key and the value of the enum will be the same since it's a key lookup rather than a value lookup.
    – rpivovar
    Commented Nov 5, 2020 at 13:44
  • 3
    aha! found way down in the answers, I can confirm this solution works without any any or type complains, AND it works when the enum names themselves do not match their respective actual values (as many hacky solutions on this page suggest or use). Should be the accepted answer, especially coming originally from TypeScript's GitHub. Commented Mar 17, 2021 at 7:38
  • 2
    This works for every case you need to check. Perfect answer. Commented Apr 26, 2021 at 16:49
  • 1
    this does not narrows the type, just returns a boolean
    – Danielo515
    Commented Apr 1, 2022 at 11:47
  • 1
    @GeorgeDimitriadis It was an extra edit someone added to my answer, I reverted it to the original version. Commented Jan 8 at 11:25
41
export enum YourEnum {
   enum1 = 'enum1',
   enum2 = 'enum2',
   enum3 = 'enum3',
}

const status = 'enumnumnum';

if (!Object.values(YourEnum)?.includes(status)) {
     throw new UnprocessableEntityResponse('Invalid enum val');
}
6
  • 3
    I like this the most Commented Feb 6, 2020 at 14:10
  • 3
    So this example is just using key==value and that's the reason it works, right? If key!=value, it would check by key. Commented Mar 2, 2020 at 20:03
  • 47
    Actually this case works only because of a coincident. 'enum1' would only be found because it's the same value as the key. But if the keys differ from the values it doesn't work.
    – lukas_o
    Commented Apr 20, 2020 at 17:34
  • 7
    @lukas_o is right about that. This solution looks clear at first glance but it is definitely bug-prone.
    – piotros
    Commented Jun 9, 2020 at 14:01
  • Yes this is a bad example and should not be used as is. The in keyword matches keys, not values, so you need a better solution for the if statement, such as Object.values(YourEnum).includes(status) or an indexOf solution for ES5.
    – VictorB
    Commented Mar 5, 2021 at 21:30
21

There is a very simple and easy solution to your question:

var districtId = 210;

if (DistrictsEnum[districtId] != null) {

// Returns 'undefined' if the districtId not exists in the DistrictsEnum 
    model.handlingDistrictId = districtId;
}
7
  • Thank you Ester for your answer. Since I've moved from programming to fulltime UX Design I can't verify this anymore. @crowd, let me know if I the accepted answer is still the way to go in 2019! Cheers
    – Tim Schoch
    Commented Mar 28, 2019 at 17:20
  • 2
    @TimSchoch I can confirm this works very well at least for numeric enums. This is the most elegant solution imho.
    – ppulwey
    Commented Apr 4, 2019 at 13:23
  • @PatrickP. can you confirm that the solution proposed by Ester works for string enums too?
    – Tim Schoch
    Commented Apr 11, 2019 at 14:36
  • 1
    @TimSchoch Yes! It works for strings too. like a Dictionary - you can use any type for the keys in the dictionary. Commented Apr 14, 2019 at 8:06
  • 16
    Note that this does NOT work for string enums if the enum uses string initializers with different values than the enum member names. See @Xiv's answer below: stackoverflow.com/a/47755096/4752920
    – kcstricks
    Commented May 22, 2019 at 17:08
19

Type assertion is un-avoidable. Following up on

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

I found one alternative that wasn't mentioned so thought I'd share my fix for it:

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

I find this more truthful because we usually come in typesafe(with a string) and want to compare it to the enum; it'd be a bit reckless to typecast it to any(reason: never do this) or Vehicle(reason: likely untruthful). Instead, typecasting the Object.values() output to an array of strings is in-fact very much real.

3
  • I like to use two lines: const options: string[] = Object.values(TheEnum); const isInTheEnum = options.includes(theValue);
    – DaveBagler
    Commented Dec 24, 2020 at 16:15
  • 2
    I think this one is the most readable. This is what I ended up using.
    – jcollum
    Commented Apr 28, 2022 at 21:05
  • 2
    This should be marked as the answer. Agree with @jcollum, it's the most readable and most truthful Commented Sep 13, 2023 at 4:52
10
export enum UserLevel {
  Staff = 0,
  Leader,
  Manager,
}

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

Difference result in log:

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

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

The solution, we need to remove key as a number.

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

For anyone who comes here looking to validate if a string is one of the values of an enum and type convert it, I wrote this function that returns the proper type and returns undefined if the string is not in the enum.

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

As an example:

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

Update:

I've found that whenever I need to check if a value exists in an enum, I don't really need an enum and that a type is a better solution. So my enum in my original answer becomes:

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

Original answer:

For clarity, I like to break the values and includes calls onto separate lines. Here's an example:

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);
}
2
  • 7
    The problem with type ValidColors is that you can't write an isValidColor(color: string): boolean function for it: since type ValidColors doesn't exist at runtime, there is nothing to check against. This is a problem if you're trying to go from an un-typed API (e.g. user input) to a ValidColor and reject invalid inputs.
    – mamacdon
    Commented Feb 2, 2021 at 21:30
  • 2
    @mamacdon, absolutely. That's why I left my original answer as well. I've just noticed that most often, when I'm reaching for an enum, it's in situations where I'm validating things like Vue component properties, and in those cases, a type works.
    – DaveBagler
    Commented Feb 5, 2021 at 3:11
1

The following function returns another function which acts as a type predicate for the input enum (assuming it is a string style enum).

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

It works in TypeScript 4.2.4, but I have not tested earlier versions.

The main interesting part is the EnumClass[keyof EnumClass] return type. When such a type is an enum in TypeScript, it returns the original type of the enum where EnumClass is the type of the runtime enum class.

For an example of how to use this construction, suppose we have the following enum:

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

Direction is both a type as well as a runtime object. We can generate a type predicate for Direction and use it like so:

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;
}
2
  • Thanks, this is what I was after. One question: what's the purpose of the reverseMapping?
    – David Good
    Commented Oct 9, 2021 at 20:31
  • @DavidGood that just makes it easier to convert into an existence check. You could also use a Set<string> or possibly even enumClass itself by checking if the input exists in the enumClass. Commented Oct 27, 2021 at 0:29
1

I made a handy function that can be used by an enum type. Check this link. It is also type predicate.

function isEnum<EV, ET extends { [key: string]: EV }>(enumValue: EV, enumType: ET): enumValue is ET[keyof ET] {
  return Object.values(enumType).includes(enumValue);
}

Examples:

enum MyFavoriteColor {
  RED = '#FF0000',
  GREEN = '#00FF00',
  BLUE = '#0000FF',
}

const color1 = MyFavoriteColor.RED
if (isEnum(color1, MyFavoriteColor)) {
  console.log(`color '${color1}' is MyFavoriteColor`)
} else {
  console.log(`color '${color1}' is not MyFavoriteColor`)
}

const color2 = '#FF0000'
if (isEnum(color2, MyFavoriteColor)) {
  console.log(`color '${color2}' is MyFavoriteColor`)
} else {
  console.log(`color '${color2}' is not MyFavoriteColor`)
}

const color3 = 'RED'
if (isEnum(color3, MyFavoriteColor)) {
  console.log(`color '${color3}' is MyFavoriteColor`)
} else {
  console.log(`color '${color3}' is not MyFavoriteColor`)
}

Output:

[LOG]: "color '#FF0000' is MyFavoriteColor" 
[LOG]: "color '#FF0000' is MyFavoriteColor" 
[LOG]: "color 'RED' is not MyFavoriteColor"  
0

If you there to find how to check union contain specific value, there is solution:

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

For my case, this worked. I had to typecast my string to Enum.

export declare enum UserType {
    REGULAR_USER = "regular",
    ADMIN_USER = "admin",
}
const type = "admin"
if(Object.values(UserType).includes(type as UserType))
  console.log('You are admin')
-2
enum ServicePlatform {
    UPLAY = "uplay",
    PSN = "psn",
    XBL = "xbl"
}

becomes:

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

so

ServicePlatform.UPLAY in ServicePlatform // false

SOLUTION:

ServicePlatform.UPLAY.toUpperCase() in ServicePlatform // true
1
  • that only works because your keys and values in enum are the same text upper/lower case Commented Nov 17, 2020 at 17:15

Not the answer you're looking for? Browse other questions tagged or ask your own question.