typescript - Guard de tip generic pentru enum


Pot să scriu un protecție de tip non-generic pentru a verifica dacă un șir dat este membru al unui enum de șiruri astfel:

enum MyEnum {
  Thing1 = 'thing one',
  Thing2 = 'thing two',
}

const isMyEnum = (token: any): token is MyEnum => {
  return Object.values(MyEnum).includes(token as MyEnum);
};

Este posibil să facem acest lucru generic, astfel încât să pot reutiliza aceeași logică de verificare pentru multe enum-uri de șiruri diferite?

Răspuns #1

Vrei să spui așa?

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

DeciisSomeEnum produce funcții de tip guard din obiecte enum. Tipul T[keyof T] înseamnă tipurile valorilor proprietăților din T.

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

Când apelezi isSomeEnum(MyEnum), tipul T este dedus ca typeof MyEnum, iar apoi T[keyof T] sunt valorile proprietăților acestuia, care este MyEnum.

Sper că asta ajută. Mult noroc!

Link către cod

Răspunsul #2

Enumurile de tip string și enumurile de tip number din TS generează cod JS foarte diferit.

Răspunsul acceptat funcționează pentru cazul OP-ului cu enumuri de tip șir.

Dar cineva care folosește enumerații numerice ar putea crede naiv că va funcționa și pentru cazul lor. Fiți atenți.

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

Teren de joacă