Как получить массив значений перечисления (enum) в TypeScript

👋
Хочешь поучаствовать в жизни сайта? Мы ищем авторов!

Вот generic-функция, которая работает как с числовыми enum'ами, так и со строковыми:

type EnumObject = {[key: string]: number | string};
type EnumObjectEnum<E extends EnumObject> = E extends {[key: string]: infer ET | string} ? ET : never;

function getEnumValues<E extends EnumObject>(enumObject: E): EnumObjectEnum<E>[] {
  return Object.keys(enumObject)
    .filter(key => Number.isNaN(Number(key)))
    .map(key => enumObject[key] as EnumObjectEnum<E>);
}

Работает на TypeScript 4 и 3.6+.

Использование

На числовом перечислении:

enum NumEnum {
    A,
    B,
    C,
}

// Компилятор определяет тип numEnumValues как NumEnum[]
let numEnumValues = getEnumValues(NumEnum);

На строковом перечислении:

enum StringEnum {
    A = "a",
    B = "b",
    C = "c",
}

// Компилятор определяет тип stringEnumValues как StringEnum[]
let stringEnumValues = getEnumValues(StringEnum);

Известные проблемы

К сожалению, функция проходит тайп-чекинг не очень хорошо, если enum составлен из разных типов (из чисел и строк одновременно), по крайней мере на момент TypeScript 4.6:

enum MixedEnum {
    A = "a",
    B = 2,
    C = "c",
}

// Тип mixedEnumValues неправильно определяется как MixedEnum.B[]
let mixedEnumValues = getEnumValues(MixedEnum);

// Можно избежать этой проблемы, если задать тип явно одним из способов:
let mixedEnumValues: MixedEnum[] = getEnumValues(MixedEnum);
let mixedEnumValues = getEnumValues(MixedEnum) as MixedEnum[];

Послесловие

Вот шикарный пост от Zhenghao про программирование на уровне типов в TypeScript. Я из него многое почерпнул!

Zhenghao’s site
The official site of Zhenghao He, a software engineer and a TypeScript/JavaScript enthusiast.

Материал подготовлен с ❤️ редакцией Кухни IT.

Олег Ямников

Олег Ямников

Главный кухонный корреспондент.