Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Generic enum type guard

Tags:

typescript

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

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?

like image 723
tuff Avatar asked Oct 08 '19 00:10

tuff


1 Answers

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

Playground

like image 200
Justin AnyhowStep Avatar answered Nov 16 '22 02:11

Justin AnyhowStep