Enum as Parameter in TypeScript

I agree with @Tarh. Enums in TypeScript are just Javascript objects without a common interface or prototype (and if they are const enum, then they are not even objects), so you cannot restrict types to "any enum".

The closest I could get is something like the following:

enum E1 {
    A, B, C
}
enum E2 {
    X, Y, Z
}

// make up your own interface to match TypeScript enums
// as closely as possible (not perfect, though)
interface Enum {
    [id: number]: string
}

function getRandomElementOfEnum(e: Enum): string {
   let length = Object.keys(e).length / 2;
   return e[Math.floor((Math.random() * length))];
}

This works for all enums (without custom initializers), but it would also accept other arrays as input (and then fail because the method body relies on the very specific key structure that TypeScript enums have).

So unless you have a real need for such a "generic" function, make typesafe functions for the individual enum types (or a union type like E1|E2|E3) that you actually need.

And if you do have this need (and this might very well be an X-Y-problem that can be solved in a better, completely different way given more context), use any, because you have left typesafe territory anyway.


You can do better than any:

enum E1 {
    A, B, C
}
enum E2 {
    X, Y, Z
}

function getRandomElementOfEnum(e: { [s: number]: string }): number {
    /* insert working implementation here */
    return undefined;
}

// OK
var x: E1 = getRandomElementOfEnum(E1);
// Error
var y: E2 = getRandomElementOfEnum(window);
// Error
var z: string = getRandomElementOfEnum(E2);

It's not possible to ensure the parameter is an enum, because enumerations in TS don't inherit from a common ancestor or interface.

TypeScript brings static analysis. Your code uses dynamic programming with Object.keys and e[dynamicKey]. For dynamic codes, the type any is convenient.

Your code is buggy: length() doesn't exists, e[Math.floor((Math.random() * length)+1)] returns a string or an integer, and the enumeration values can be manually set…

Here is a suggestion:

function getRandomElementOfEnum<E>(e: any): E {
    var keys = Object.keys(e),
        index = Math.floor(Math.random() * keys.length),
        k = keys[index];
    if (typeof e[k] === 'number')
        return <any>e[k];
    return <any>parseInt(k, 10);
}

function display(a: Color) {
    console.log(a);
}

enum Color { Blue, Green };
display(getRandomElementOfEnum<Color>(Color));

Ideally, the parameter type any should be replaced by typeof E but the compiler (TS 1.5) can't understand this syntax.