Как проверить, существует ли значение в enum в TypeScript?
Проверка существования значения в enum: основные подходы
В TypeScript есть несколько способов проверить, существует ли значение в enum. Выбор подхода зависит от типа enum (строковый или числовой) и от того, как вы планируете использовать результат проверки.
1. Для строковых enum (ваш случай)
Самый простой и надёжный способ — использовать Object.values() вместе с приведением типа:
enum Color {
Red = 'RED',
Green = 'GREEN',
Blue = 'BLUE'
}
function isValidColor(value: string): value is Color {
return Object.values(Color).includes(value as Color);
}
// Использование
const userInput: string = 'RED';
if (isValidColor(userInput)) {
console.log(`Допустимый цвет: ${userInput}`);
// Здесь TypeScript знает, что userInput — это Color
} else {
console.log(`Недопустимое значение: ${userInput}`);
}
Ключевой момент: includes(value as Color) — это приведение типа, которое говорит TypeScript: "доверься мне, я знаю, что делаю". На самом деле в рантайме проверка работает корректно, так как Object.values(Color) возвращает массив строк ['RED', 'GREEN', 'BLUE'].
2. Для числовых enum
С числовыми enum ситуация сложнее, потому что TypeScript создаёт двунаправленное отображение (ключ → значение и значение → ключ):
enum Status {
Active = 1,
Inactive = 2,
Pending = 3
}
// Object.values(Status) вернёт: [1, 2, 3, 'Active', 'Inactive', 'Pending']
// Это не очень удобно для проверки
function isValidStatus(value: number): value is Status {
return Object.values(Status).includes(value as Status);
}
// Но лучше использовать более точную проверку:
function isValidStatusSafe(value: number): boolean {
return [Status.Active, Status.Inactive, Status.Pending].includes(value);
}
3. Универсальное решение для любых enum
Можно создать вспомогательную функцию, которая работает с любым enum:
function isEnumValue<T extends Record<string, string | number>>(
enumObj: T,
value: unknown
): value is T[keyof T] {
const values = Object.values(enumObj);
// Для числовых enum отфильтровываем строковые ключи
const enumValues = values.filter(v => typeof v === 'number' || typeof v === 'string');
return enumValues.includes(value as T[keyof T]);
}
// Использование
enum Color {
Red = 'RED',
Green = 'GREEN'
}
enum Status {
Active = 1,
Inactive = 2
}
console.log(isEnumValue(Color, 'RED')); // true
console.log(isEnumValue(Color, 'YELLOW')); // false
console.log(isEnumValue(Status, 1)); // true
console.log(isEnumValue(Status, 5)); // false
4. Type Guard для автодополнения
Если вы хотите, чтобы после проверки TypeScript "знал" тип значения, используйте type guard:
function isColor(value: string): value is Color {
return Object.values(Color).includes(value as Color);
}
const input: string = 'GREEN';
if (isColor(input)) {
// Здесь input имеет тип Color, а не string
console.log(input.toLowerCase()); // Автодополнение работает!
}
Важные замечания:
- Для const enum (объявленных с ключевым словом
const) этот подход не сработает, так как const enum не существует в рантайме. Вам придётся использовать обычный enum или массив констант. - Производительность:
Object.values()создаёт новый массив при каждом вызове. Для частых проверок лучше кешировать массив значений. - Типобезопасность: Использование
as— это компромисс. Если вы уверены в логике, это безопасно, но всегда тестируйте свой код.
В вашем случае рекомендую использовать первый подход с функцией isValidColor — он простой, понятный и эффективный для строковых enum.
Альтернативный подход: использование Map или Set
Если вам нужно часто проверять значения enum и важна производительность, лучше заранее создать Set или Map со всеми допустимыми значениями:
enum Color {
Red = 'RED',
Green = 'GREEN',
Blue = 'BLUE'
}
// Создаём Set один раз
const validColors = new Set(Object.values(Color));
function isValidColor(value: string): boolean {
return validColors.has(value);
}
// Использование
console.log(isValidColor('RED')); // true
console.log(isValidColor('YELLOW')); // false
Преимущества:
- Быстрее, чем
includes()при большом количестве проверок (O(1) vs O(n)). - Не нужно использовать приведение типов.
- Легко расширять — просто добавьте новые значения в enum.
Недостаток: Не является type guard, поэтому после проверки TypeScript не будет знать точный тип. Если вам нужен type guard, комбинируйте оба подхода:
const validColors = new Set(Object.values(Color));
function isColor(value: string): value is Color {
return validColors.has(value as Color);
}
Этот подход особенно удобен, когда enum большой и проверки выполняются часто (например, в цикле или внутри горячего пути кода).
Ответов пока нет.
Войдите чтобы оставить ответ