tru7
tru7

Reputation: 7222

typescript string enum, reverse mapping equivalent

I have a string enum and need to check if a literal pertains to the enum. Reverse mapping does not work on string enums.

Supposing

enum Animals{
    cat="c";
    dog="d";
    fish="f";
}

let animal= "d";

is animal a member of Animals ? Considering the enum an object you can iterate and check:

function inEnum(what, enu):boolean{
    for (let item in enu){
        if (enu[item]==what){
            return true;
        }
    }
    return false;
}

Is there a better way?, may this technique break in future versions?

Upvotes: 1

Views: 2667

Answers (2)

Jeff Lau
Jeff Lau

Reputation: 442

The ts-enum-util (github, npm) lib supports validation of enum names/values and type-safe value->key and key->value lookups with run-time validation and the option to either throw an error or return a default value.

Examples:

import {$enum} from "ts-enum-util";

enum Animals{
    cat="c";
    dog="d";
    fish="f";
}

let animal= "d"; 

// true
const isAnimal = $enum(Animals).isValue(animal);

// the "isValue" method is a custom type guard
if ($enum(Animals).isValue(animal)) {
    // type of "animal" in here is "Animals" instead of "string"
}

// type: ("cat" | "dog" | "fish")
// value: "dog"
const name = $enum(Animals).getKeyOrThrow(animal); 

Upvotes: 3

Stewart_R
Stewart_R

Reputation: 14495

Before answering the question directly, it's worth just mentioning that TypeScript supports a Union Type which is often a better fit for this type of thing than a string enum. Example:

type Animal = 'cat' | 'dog' | 'fish';

let myAnimal1: Animal = 'cat'; // ok
let myAnimal2: Animal = 'buttercup'; // compile-time error "'buttercup' is not assignable to type Animal"

This type of approach has the benefit of letting you know at compile-time whether a value is valid for the Animals type.


Now, to answer your question about determining if a value is in an enum at run-time, we have the in operator which we can use to refactor your inEnum function as follows:

let inEnum = (val, enumObj) => val in enumObj;

inEnum("d", Animals) //evaluates to true
inEnum("z", Animals) //evaluates to false

or even drop the function call altogether and just use the in operator directly:

"d" in Animals //evaluates to true
"z" in Animals //evaluates to false

There is, however, nothing to suggest that your own approach above would ever break in future versions.

Upvotes: 1

Related Questions