Generic enum type guard


I can write a non-generic type guard to check if a given string is a member of a string enum like this:

<pre class="lang-js prettyprint-override">enum MyEnum { Thing1 = 'thing one', Thing2 = 'thing two', } const isMyEnum = (token: any): token is MyEnum => { return Object.values(MyEnum).includes(token as MyEnum); };

Is it possible to make this generic, so that I could re-use the same checking logic for many different string enums?


You mean like this?

const isSomeEnum = <T>(e: T) => (token: any): token is T[keyof T] => Object.values(e).includes(token as T[keyof T]);

SoisSomeEnum produces type guard functions from enum objects. The type T[keyof T] means the types of the property values of T.

const isMyEnum = isSomeEnum(MyEnum); // const isMyEnum: (token: any) => token is MyEnum

When you call isSomeEnum(MyEnum), the type T is inferred as typeof MyEnum, and then T[keyof T] is the property values of that, which is MyEnum.

Hope that helps. Good luck!

Link to code


TS string enums and number enums have very different JS emits.

The accepted answer works for OP's case of string enums.

But someone using number enums may naively think that it will also work for their use case. Be careful.

//number enum here enum E { A, B, C, } const isSomeEnum = <T>(e: T) => (token: any): token is T[keyof T] => (Object as any).values(e).includes(token as T[keyof T]); console.log(isSomeEnum(E)("A")); //expected false, actual true console.log(isSomeEnum(E)(0)); //expected true , actual true function isSomeEnum2<T> (e: T) : (token: unknown) => token is T[keyof T] { const keys = Object.keys(e) .filter((k) => { return !/^\d/.test(k); }); const values = keys.map((k) => { return (e as any)[k]; }); return (token: unknown): token is T[keyof T] => { return values.includes(token); }; }; console.log(isSomeEnum2(E)("A")); //expected false, actual false console.log(isSomeEnum2(E)(0)); //expected true , actual true