- Home »

Как использовать перечисления (Enums) в TypeScript
Когда разрабатываешь серверные приложения на TypeScript, часто сталкиваешься с необходимостью работать с фиксированными наборами значений — статусы запросов, типы пользователей, коды ошибок HTTP. Именно здесь на помощь приходят перечисления (Enums), которые позволяют сделать код более читаемым, типобезопасным и менее подверженным ошибкам. Если ты работаешь с REST API, настраиваешь мониторинг сервера или пишешь скрипты автоматизации, то правильное использование Enums может значительно упростить твою жизнь и сделать код более maintainable.
Как работают перечисления в TypeScript
Enums в TypeScript — это способ задать набор именованных констант, которые могут быть как числовыми, так и строковыми. В отличие от обычных JavaScript-констант, Enums предоставляют дополнительные возможности типизации и удобство работы.
Базовый синтаксис выглядит так:
enum ServerStatus {
Online,
Offline,
Maintenance,
Error
}
// Использование
const currentStatus = ServerStatus.Online;
console.log(currentStatus); // 0 (числовое значение)
console.log(ServerStatus[0]); // "Online" (обратное получение имени)
По умолчанию TypeScript присваивает числовые значения начиная с 0, но можно задать кастомные значения:
enum HttpStatus {
OK = 200,
NotFound = 404,
InternalError = 500
}
enum LogLevel {
DEBUG = "debug",
INFO = "info",
WARNING = "warning",
ERROR = "error"
}
Пошаговая настройка и примеры использования
Давайте разберём практический пример создания серверного приложения с использованием Enums:
Шаг 1: Инициализация проекта
mkdir server-enums-example
cd server-enums-example
npm init -y
npm install typescript @types/node ts-node
npx tsc --init
Шаг 2: Создание базовых перечислений
Создай файл enums.ts
с основными перечислениями для серверного приложения:
// enums.ts
export enum ServerEnvironment {
DEVELOPMENT = "development",
STAGING = "staging",
PRODUCTION = "production"
}
export enum DatabaseStatus {
CONNECTED = "connected",
DISCONNECTED = "disconnected",
CONNECTING = "connecting",
ERROR = "error"
}
export enum UserRole {
ADMIN = "admin",
MODERATOR = "moderator",
USER = "user",
GUEST = "guest"
}
export enum ApiVersion {
V1 = "v1",
V2 = "v2",
V3 = "v3"
}
// Числовые Enums для приоритетов
export enum Priority {
LOW = 1,
MEDIUM = 2,
HIGH = 3,
CRITICAL = 4
}
Шаг 3: Практическое применение в серверном коде
// server.ts
import { ServerEnvironment, DatabaseStatus, UserRole, Priority } from './enums';
class ServerManager {
private environment: ServerEnvironment;
private dbStatus: DatabaseStatus;
constructor(env: ServerEnvironment) {
this.environment = env;
this.dbStatus = DatabaseStatus.DISCONNECTED;
}
// Метод для проверки доступа на основе роли
checkAccess(userRole: UserRole, requiredRole: UserRole): boolean {
const roleHierarchy = {
[UserRole.GUEST]: 0,
[UserRole.USER]: 1,
[UserRole.MODERATOR]: 2,
[UserRole.ADMIN]: 3
};
return roleHierarchy[userRole] >= roleHierarchy[requiredRole];
}
// Логирование с приоритетом
log(message: string, priority: Priority): void {
const timestamp = new Date().toISOString();
const envPrefix = this.environment.toUpperCase();
if (priority >= Priority.HIGH) {
console.error(`[${envPrefix}] ${timestamp} CRITICAL: ${message}`);
} else {
console.log(`[${envPrefix}] ${timestamp} ${Priority[priority]}: ${message}`);
}
}
}
// Использование
const server = new ServerManager(ServerEnvironment.PRODUCTION);
server.log("Server started", Priority.HIGH);
console.log(server.checkAccess(UserRole.MODERATOR, UserRole.USER)); // true
Типы перечислений и их особенности
Тип Enum | Преимущества | Недостатки | Когда использовать |
---|---|---|---|
Числовые | Компактные, быстрые операции сравнения | Нечитаемые в логах, могут измениться при рефакторинге | Внутренние флаги, приоритеты |
Строковые | Читаемые, стабильные значения | Больше памяти, медленнее сравнение | API responses, конфигурация |
Const enum | Встраиваются в код, нет runtime overhead | Нельзя итерировать, проблемы с модулями | Константы времени компиляции |
Продвинутые техники и паттерны
Const Enums для оптимизации
// Const enum полностью встраивается в код при компиляции
const enum ResponseCode {
SUCCESS = 200,
NOT_FOUND = 404,
SERVER_ERROR = 500
}
// Компилируется в: if (status === 200)
if (status === ResponseCode.SUCCESS) {
// handle success
}
Reverse mapping для числовых enum
enum ProcessStatus {
PENDING = 1,
RUNNING = 2,
COMPLETED = 3,
FAILED = 4
}
// Получение имени по значению
function getStatusName(status: number): string {
return ProcessStatus[status] || "Unknown";
}
console.log(getStatusName(2)); // "RUNNING"
Создание утилит для работы с Enums
// utils.ts
export class EnumUtils {
static getValues>(enumObject: T): T[keyof T][] {
return Object.values(enumObject);
}
static getKeys>(enumObject: T): string[] {
return Object.keys(enumObject);
}
static isValidValue>(
enumObject: T,
value: any
): value is T[keyof T] {
return Object.values(enumObject).includes(value);
}
}
// Использование
const validRoles = EnumUtils.getValues(UserRole);
const isValidRole = EnumUtils.isValidValue(UserRole, "admin"); // true
Интеграция с популярными библиотеками
Использование с Express.js
import express from 'express';
import { UserRole, ApiVersion } from './enums';
const app = express();
// Middleware для проверки версии API
app.use('/api/:version', (req, res, next) => {
const version = req.params.version as ApiVersion;
if (!EnumUtils.isValidValue(ApiVersion, version)) {
return res.status(400).json({ error: 'Invalid API version' });
}
next();
});
// Защищённый роут с проверкой роли
app.get('/admin', (req, res) => {
const userRole = req.user?.role as UserRole;
if (userRole !== UserRole.ADMIN) {
return res.status(403).json({ error: 'Access denied' });
}
res.json({ message: 'Admin panel access granted' });
});
Конфигурация с переменными окружения
// config.ts
import { ServerEnvironment } from './enums';
export class Config {
static getEnvironment(): ServerEnvironment {
const env = process.env.NODE_ENV;
switch (env) {
case 'development':
return ServerEnvironment.DEVELOPMENT;
case 'staging':
return ServerEnvironment.STAGING;
case 'production':
return ServerEnvironment.PRODUCTION;
default:
return ServerEnvironment.DEVELOPMENT;
}
}
static isDevelopment(): boolean {
return this.getEnvironment() === ServerEnvironment.DEVELOPMENT;
}
}
Автоматизация и скрипты
Enums отлично подходят для создания скриптов автоматизации серверных задач:
// deployment-script.ts
enum DeploymentStage {
BUILD = "build",
TEST = "test",
DEPLOY = "deploy",
VERIFY = "verify",
ROLLBACK = "rollback"
}
class DeploymentManager {
async executeStage(stage: DeploymentStage): Promise {
console.log(`Executing stage: ${stage}`);
switch (stage) {
case DeploymentStage.BUILD:
return this.buildApplication();
case DeploymentStage.TEST:
return this.runTests();
case DeploymentStage.DEPLOY:
return this.deployToServer();
case DeploymentStage.VERIFY:
return this.verifyDeployment();
case DeploymentStage.ROLLBACK:
return this.rollbackDeployment();
default:
throw new Error(`Unknown deployment stage: ${stage}`);
}
}
private async buildApplication(): Promise {
// Логика сборки
return true;
}
// Другие методы...
}
// Использование в скрипте
const deployment = new DeploymentManager();
const stages = [
DeploymentStage.BUILD,
DeploymentStage.TEST,
DeploymentStage.DEPLOY,
DeploymentStage.VERIFY
];
stages.forEach(async (stage) => {
const success = await deployment.executeStage(stage);
if (!success) {
await deployment.executeStage(DeploymentStage.ROLLBACK);
process.exit(1);
}
});
Мониторинг и метрики
// monitoring.ts
enum MetricType {
CPU_USAGE = "cpu_usage",
MEMORY_USAGE = "memory_usage",
DISK_USAGE = "disk_usage",
NETWORK_IO = "network_io"
}
enum AlertLevel {
INFO = 1,
WARNING = 2,
ERROR = 3,
CRITICAL = 4
}
class MonitoringSystem {
private metrics: Map = new Map();
updateMetric(type: MetricType, value: number): void {
this.metrics.set(type, value);
this.checkAlerts(type, value);
}
private checkAlerts(type: MetricType, value: number): void {
let alertLevel: AlertLevel;
switch (type) {
case MetricType.CPU_USAGE:
if (value > 90) alertLevel = AlertLevel.CRITICAL;
else if (value > 70) alertLevel = AlertLevel.WARNING;
else alertLevel = AlertLevel.INFO;
break;
case MetricType.MEMORY_USAGE:
if (value > 85) alertLevel = AlertLevel.ERROR;
else if (value > 60) alertLevel = AlertLevel.WARNING;
else alertLevel = AlertLevel.INFO;
break;
default:
alertLevel = AlertLevel.INFO;
}
if (alertLevel >= AlertLevel.WARNING) {
this.sendAlert(type, value, alertLevel);
}
}
private sendAlert(type: MetricType, value: number, level: AlertLevel): void {
console.log(`ALERT [${AlertLevel[level]}]: ${type} = ${value}%`);
}
}
Интересные факты и нестандартные применения
Несколько полезных трюков, которые могут пригодиться в работе:
- Битовые флаги: Можно использовать числовые Enums для создания битовых флагов
- Enum как тип Union: TypeScript автоматически создаёт Union type из значений Enum
- Computed enum values: Можно использовать вычисляемые значения в Enums
// Битовые флаги
enum Permissions {
READ = 1,
WRITE = 2,
EXECUTE = 4,
DELETE = 8
}
const userPermissions = Permissions.READ | Permissions.WRITE;
const hasWriteAccess = (userPermissions & Permissions.WRITE) === Permissions.WRITE;
// Computed values
enum TimeConstants {
SECOND = 1000,
MINUTE = SECOND * 60,
HOUR = MINUTE * 60,
DAY = HOUR * 24
}
Лучшие практики и рекомендации
Основываясь на опыте работы с серверными приложениями, вот несколько важных рекомендаций:
- Используй строковые Enums для API: Они более читаемы в логах и стабильны при рефакторинге
- Избегай смешивания типов: Не используй одновременно числовые и строковые значения в одном Enum
- Создавай утилиты для валидации: Это поможет при работе с внешними данными
- Используй const enum для performance-critical кода: Но помни об ограничениях
- Именуй Enums в единственном числе:
UserRole
вместоUserRoles
Для серверных приложений, особенно если планируешь деплой на VPS или выделенном сервере, правильное использование Enums может значительно упростить мониторинг, логирование и обслуживание.
Заключение и рекомендации
Enums в TypeScript — это мощный инструмент для создания maintainable серверного кода. Они особенно полезны при работе с конфигурацией, статусами, ролями пользователей и другими фиксированными наборами значений. Использование Enums делает код более читаемым, менее подверженным ошибкам и упрощает рефакторинг.
Для серверных приложений рекомендую:
- Использовать строковые Enums для внешних API и конфигурации
- Числовые Enums подходят для внутренних флагов и приоритетов
- Создавать утилиты для валидации и работы с Enums
- Применять Enums в системах мониторинга и алертинга
- Использовать их для создания типобезопасных скриптов автоматизации
Правильное применение Enums поможет создать более robust и maintainable серверные приложения, что особенно важно при работе в продакшене.
В этой статье собрана информация и материалы из различных интернет-источников. Мы признаем и ценим работу всех оригинальных авторов, издателей и веб-сайтов. Несмотря на то, что были приложены все усилия для надлежащего указания исходного материала, любая непреднамеренная оплошность или упущение не являются нарушением авторских прав. Все упомянутые товарные знаки, логотипы и изображения являются собственностью соответствующих владельцев. Если вы считаете, что какой-либо контент, использованный в этой статье, нарушает ваши авторские права, немедленно свяжитесь с нами для рассмотрения и принятия оперативных мер.
Данная статья предназначена исключительно для ознакомительных и образовательных целей и не ущемляет права правообладателей. Если какой-либо материал, защищенный авторским правом, был использован без должного упоминания или с нарушением законов об авторском праве, это непреднамеренно, и мы исправим это незамедлительно после уведомления. Обратите внимание, что переиздание, распространение или воспроизведение части или всего содержимого в любой форме запрещено без письменного разрешения автора и владельца веб-сайта. Для получения разрешений или дополнительных запросов, пожалуйста, свяжитесь с нами.