
How to Use Enums in TypeScript
If you’ve been building applications in TypeScript, especially server-side applications that require robust configuration management and API handling, you’ve probably encountered situations where you need to represent fixed sets of named constants. Enter TypeScript enums β a powerful feature that brings structure and type safety to your constant values. Whether you’re managing server response codes, database connection states, user roles in your hosting management panel, or configuration flags for your VPS deployment scripts, enums provide a clean, maintainable way to organize these values. This comprehensive guide will walk you through everything you need to know about TypeScript enums, from basic implementation to advanced patterns that’ll make your server-side code more reliable and easier to maintain.
How TypeScript Enums Work Under the Hood
TypeScript enums are essentially a way to give friendly names to sets of numeric or string values. When you compile TypeScript to JavaScript, enums get transpiled into objects that provide both forward (name β value) and reverse (value β name) mappings for numeric enums, while string enums only provide forward mapping.
Here’s what happens when you create a basic numeric enum:
// TypeScript
enum ServerStatus {
OFFLINE,
STARTING,
ONLINE,
MAINTENANCE
}
// Compiled JavaScript (simplified)
var ServerStatus;
(function (ServerStatus) {
ServerStatus[ServerStatus["OFFLINE"] = 0] = "OFFLINE";
ServerStatus[ServerStatus["STARTING"] = 1] = "STARTING";
ServerStatus[ServerStatus["ONLINE"] = 2] = "ONLINE";
ServerStatus[ServerStatus["MAINTENANCE"] = 3] = "MAINTENANCE";
})(ServerStatus || (ServerStatus = {}));
This creates an object where both ServerStatus.OFFLINE === 0
and ServerStatus[0] === "OFFLINE"
are true. This reverse mapping is particularly useful when you're dealing with numeric status codes from APIs or database records.
String enums work differently and don't provide reverse mapping:
enum LogLevel {
ERROR = "error",
WARN = "warn",
INFO = "info",
DEBUG = "debug"
}
// Results in a simpler compiled output
var LogLevel;
(function (LogLevel) {
LogLevel["ERROR"] = "error";
LogLevel["WARN"] = "warn";
LogLevel["INFO"] = "info";
LogLevel["DEBUG"] = "debug";
})(LogLevel || (LogLevel = {}));
Setting Up and Using Enums: A Step-by-Step Guide
Let's build a practical example that you might use in a server management application. We'll create enums for various server-related configurations and show how to integrate them into your TypeScript project.
Step 1: Basic Enum Declaration
// server-types.ts
export enum ServerType {
SHARED = "shared",
VPS = "vps",
DEDICATED = "dedicated",
CLOUD = "cloud"
}
export enum ServerRegion {
US_EAST = "us-east-1",
US_WEST = "us-west-2",
EU_CENTRAL = "eu-central-1",
ASIA_PACIFIC = "ap-southeast-1"
}
export enum ResourceStatus {
PROVISIONING,
ACTIVE,
SUSPENDED,
TERMINATED
}
Step 2: Using Enums in Interfaces and Classes
// server-config.ts
import { ServerType, ServerRegion, ResourceStatus } from './server-types';
interface ServerConfiguration {
id: string;
type: ServerType;
region: ServerRegion;
status: ResourceStatus;
specs: {
cpu: number;
ram: number;
storage: number;
};
}
class ServerManager {
private servers: Map = new Map();
createServer(config: Omit): string {
const id = this.generateId();
const server: ServerConfiguration = {
...config,
id,
status: ResourceStatus.PROVISIONING
};
this.servers.set(id, server);
this.provisionServer(server);
return id;
}
private async provisionServer(server: ServerConfiguration): Promise {
console.log(`Provisioning ${server.type} server in ${server.region}...`);
// Simulate provisioning time based on server type
const provisioningTime = this.getProvisioningTime(server.type);
await this.delay(provisioningTime);
server.status = ResourceStatus.ACTIVE;
console.log(`Server ${server.id} is now active`);
}
private getProvisioningTime(type: ServerType): number {
switch (type) {
case ServerType.SHARED:
return 1000; // 1 second
case ServerType.VPS:
return 3000; // 3 seconds
case ServerType.DEDICATED:
return 10000; // 10 seconds
case ServerType.CLOUD:
return 2000; // 2 seconds
default:
return 5000; // fallback
}
}
private delay(ms: number): Promise {
return new Promise(resolve => setTimeout(resolve, ms));
}
private generateId(): string {
return `srv_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
}
}
Step 3: Enum Validation and Type Guards
// validation.ts
import { ServerType, ServerRegion } from './server-types';
// Type guard functions
export function isValidServerType(value: string): value is ServerType {
return Object.values(ServerType).includes(value as ServerType);
}
export function isValidServerRegion(value: string): value is ServerRegion {
return Object.values(ServerRegion).includes(value as ServerRegion);
}
// API request handler example
export function handleServerCreationRequest(requestBody: any) {
const { type, region, specs } = requestBody;
if (!isValidServerType(type)) {
throw new Error(`Invalid server type: ${type}. Valid types: ${Object.values(ServerType).join(', ')}`);
}
if (!isValidServerRegion(region)) {
throw new Error(`Invalid region: ${region}. Valid regions: ${Object.values(ServerRegion).join(', ')}`);
}
// Type-safe from this point onwards
const manager = new ServerManager();
return manager.createServer({ type, region, specs });
}
Real-World Examples and Use Cases
Let's explore some practical scenarios where enums shine, especially in server management and hosting applications.
HTTP Status Code Management
enum HttpStatusCode {
// Success
OK = 200,
CREATED = 201,
ACCEPTED = 202,
NO_CONTENT = 204,
// Client Errors
BAD_REQUEST = 400,
UNAUTHORIZED = 401,
FORBIDDEN = 403,
NOT_FOUND = 404,
CONFLICT = 409,
// Server Errors
INTERNAL_SERVER_ERROR = 500,
BAD_GATEWAY = 502,
SERVICE_UNAVAILABLE = 503
}
class ApiResponse {
constructor(
public statusCode: HttpStatusCode,
public data?: any,
public message?: string
) {}
static success(data: any): ApiResponse {
return new ApiResponse(HttpStatusCode.OK, data);
}
static created(data: any): ApiResponse {
return new ApiResponse(HttpStatusCode.CREATED, data);
}
static badRequest(message: string): ApiResponse {
return new ApiResponse(HttpStatusCode.BAD_REQUEST, null, message);
}
static serverError(message: string): ApiResponse {
return new ApiResponse(HttpStatusCode.INTERNAL_SERVER_ERROR, null, message);
}
}
Configuration Management for Different Environments
enum Environment {
DEVELOPMENT = "development",
STAGING = "staging",
PRODUCTION = "production"
}
enum DatabaseType {
MYSQL = "mysql",
POSTGRESQL = "postgresql",
MONGODB = "mongodb",
REDIS = "redis"
}
interface DatabaseConfig {
type: DatabaseType;
host: string;
port: number;
database: string;
ssl: boolean;
}
class ConfigManager {
private static configs: Record> = {
[Environment.DEVELOPMENT]: {
[DatabaseType.MYSQL]: {
type: DatabaseType.MYSQL,
host: "localhost",
port: 3306,
database: "dev_app",
ssl: false
},
[DatabaseType.POSTGRESQL]: {
type: DatabaseType.POSTGRESQL,
host: "localhost",
port: 5432,
database: "dev_app",
ssl: false
},
[DatabaseType.MONGODB]: {
type: DatabaseType.MONGODB,
host: "localhost",
port: 27017,
database: "dev_app",
ssl: false
},
[DatabaseType.REDIS]: {
type: DatabaseType.REDIS,
host: "localhost",
port: 6379,
database: "0",
ssl: false
}
},
[Environment.PRODUCTION]: {
[DatabaseType.MYSQL]: {
type: DatabaseType.MYSQL,
host: "prod-mysql.example.com",
port: 3306,
database: "prod_app",
ssl: true
},
// ... other production configs
}
// ... staging configs
};
static getConfig(env: Environment, dbType: DatabaseType): DatabaseConfig {
const config = this.configs[env]?.[dbType];
if (!config) {
throw new Error(`No configuration found for ${env} environment with ${dbType} database`);
}
return config;
}
}
Server Monitoring and Alerting System
enum AlertSeverity {
LOW = 1,
MEDIUM = 2,
HIGH = 3,
CRITICAL = 4
}
enum MetricType {
CPU_USAGE = "cpu_usage",
MEMORY_USAGE = "memory_usage",
DISK_USAGE = "disk_usage",
NETWORK_IO = "network_io",
RESPONSE_TIME = "response_time"
}
interface Alert {
id: string;
severity: AlertSeverity;
metric: MetricType;
threshold: number;
currentValue: number;
serverId: string;
timestamp: Date;
}
class MonitoringSystem {
private alerts: Alert[] = [];
private thresholds: Record> = {
[MetricType.CPU_USAGE]: {
[AlertSeverity.LOW]: 60,
[AlertSeverity.MEDIUM]: 75,
[AlertSeverity.HIGH]: 85,
[AlertSeverity.CRITICAL]: 95
},
[MetricType.MEMORY_USAGE]: {
[AlertSeverity.LOW]: 70,
[AlertSeverity.MEDIUM]: 80,
[AlertSeverity.HIGH]: 90,
[AlertSeverity.CRITICAL]: 95
},
// ... other metrics
};
checkMetric(serverId: string, metric: MetricType, value: number): Alert | null {
const thresholds = this.thresholds[metric];
let severity: AlertSeverity | null = null;
// Determine severity level
if (value >= thresholds[AlertSeverity.CRITICAL]) {
severity = AlertSeverity.CRITICAL;
} else if (value >= thresholds[AlertSeverity.HIGH]) {
severity = AlertSeverity.HIGH;
} else if (value >= thresholds[AlertSeverity.MEDIUM]) {
severity = AlertSeverity.MEDIUM;
} else if (value >= thresholds[AlertSeverity.LOW]) {
severity = AlertSeverity.LOW;
}
if (severity) {
const alert: Alert = {
id: this.generateAlertId(),
severity,
metric,
threshold: thresholds[severity],
currentValue: value,
serverId,
timestamp: new Date()
};
this.alerts.push(alert);
this.triggerAlert(alert);
return alert;
}
return null;
}
private triggerAlert(alert: Alert): void {
const severityName = AlertSeverity[alert.severity];
console.log(`π¨ ${severityName} Alert: ${alert.metric} on server ${alert.serverId} is ${alert.currentValue}% (threshold: ${alert.threshold}%)`);
// In a real system, you'd send notifications here
if (alert.severity >= AlertSeverity.CRITICAL) {
this.sendCriticalAlert(alert);
}
}
private sendCriticalAlert(alert: Alert): void {
// Implementation for critical alerts (SMS, email, Slack, etc.)
console.log(`π± Sending critical alert notification for server ${alert.serverId}`);
}
private generateAlertId(): string {
return `alert_${Date.now()}_${Math.random().toString(36).substr(2, 6)}`;
}
}
Comparison Table: When to Use Different Enum Types
Enum Type | Best Use Cases | Advantages | Disadvantages | Example |
---|---|---|---|---|
Numeric Enums | Status codes, priority levels, sequential states | Reverse mapping, smaller compiled size, easy comparison | Values can change during refactoring, less readable in logs | HTTP status codes, alert severity |
String Enums | API endpoints, configuration keys, identifiers | Self-documenting, stable values, readable in logs | Larger bundle size, no reverse mapping | Server regions, database types |
Const Enums | Performance-critical code, libraries | Inlined at compile time, no runtime object | No runtime representation, limited flexibility | Internal constants, optimization scenarios |
Advanced Pattern: Computed and Const Enums
// Const enum - inlined at compile time
const enum LogLevel {
ERROR = 0,
WARN = 1,
INFO = 2,
DEBUG = 3
}
// Computed enum values
enum ServerSpecs {
BASIC_RAM = 1024,
STANDARD_RAM = BASIC_RAM * 2,
PREMIUM_RAM = BASIC_RAM * 4,
ENTERPRISE_RAM = BASIC_RAM * 8
}
// Mixed enum (not recommended, but possible)
enum MixedEnum {
A, // 0
B, // 1
C = "C",
D = "D",
E, // Error: needs explicit value after string member
}
// Better approach: separate enums
enum NumericStates {
PENDING,
PROCESSING,
COMPLETED
}
enum StringActions {
CREATE = "create",
UPDATE = "update",
DELETE = "delete"
}
Integration with Popular Tools and Packages
TypeScript enums work seamlessly with many popular tools in the Node.js ecosystem. Here are some practical integrations:
Express.js API Routes
import express from 'express';
enum ApiVersion {
V1 = "v1",
V2 = "v2",
V3 = "v3"
}
enum ApiEndpoint {
SERVERS = "servers",
USERS = "users",
BILLING = "billing"
}
class ApiRouter {
private app: express.Application;
constructor() {
this.app = express();
this.setupRoutes();
}
private setupRoutes(): void {
// Generate routes programmatically
Object.values(ApiVersion).forEach(version => {
Object.values(ApiEndpoint).forEach(endpoint => {
const path = `/api/${version}/${endpoint}`;
this.app.get(path, this.createHandler(version, endpoint));
});
});
}
private createHandler(version: ApiVersion, endpoint: ApiEndpoint) {
return (req: express.Request, res: express.Response) => {
// Route logic based on version and endpoint
const response = this.handleRequest(version, endpoint, req);
res.json(response);
};
}
private handleRequest(version: ApiVersion, endpoint: ApiEndpoint, req: express.Request) {
// Implementation details...
return { version, endpoint, timestamp: new Date().toISOString() };
}
}
Database Integration with TypeORM
import { Entity, Column, PrimaryGeneratedColumn } from 'typeorm';
export enum UserRole {
ADMIN = "admin",
MODERATOR = "moderator",
USER = "user"
}
export enum SubscriptionTier {
FREE = "free",
BASIC = "basic",
PREMIUM = "premium",
ENTERPRISE = "enterprise"
}
@Entity()
export class User {
@PrimaryGeneratedColumn()
id: number;
@Column()
email: string;
@Column({
type: "enum",
enum: UserRole,
default: UserRole.USER
})
role: UserRole;
@Column({
type: "enum",
enum: SubscriptionTier,
default: SubscriptionTier.FREE
})
subscription: SubscriptionTier;
}
// Usage in service layer
class UserService {
async upgradeUserSubscription(userId: number, newTier: SubscriptionTier) {
// Type-safe subscription upgrade logic
const validUpgrades: Record = {
[SubscriptionTier.FREE]: [SubscriptionTier.BASIC, SubscriptionTier.PREMIUM, SubscriptionTier.ENTERPRISE],
[SubscriptionTier.BASIC]: [SubscriptionTier.PREMIUM, SubscriptionTier.ENTERPRISE],
[SubscriptionTier.PREMIUM]: [SubscriptionTier.ENTERPRISE],
[SubscriptionTier.ENTERPRISE]: []
};
// Implementation...
}
}
Configuration with Environment Variables
enum ConfigKey {
PORT = "PORT",
DATABASE_URL = "DATABASE_URL",
JWT_SECRET = "JWT_SECRET",
REDIS_URL = "REDIS_URL"
}
enum NodeEnv {
DEVELOPMENT = "development",
PRODUCTION = "production",
STAGING = "staging",
TEST = "test"
}
class EnvironmentConfig {
private static instance: EnvironmentConfig;
private config: Map = new Map();
private constructor() {
this.loadConfig();
}
static getInstance(): EnvironmentConfig {
if (!EnvironmentConfig.instance) {
EnvironmentConfig.instance = new EnvironmentConfig();
}
return EnvironmentConfig.instance;
}
private loadConfig(): void {
Object.values(ConfigKey).forEach(key => {
const value = process.env[key];
if (value) {
this.config.set(key, value);
}
});
}
get(key: ConfigKey): string {
const value = this.config.get(key);
if (!value) {
throw new Error(`Configuration key ${key} is not set`);
}
return value;
}
getNodeEnv(): NodeEnv {
const env = process.env.NODE_ENV as NodeEnv;
if (!Object.values(NodeEnv).includes(env)) {
return NodeEnv.DEVELOPMENT;
}
return env;
}
isDevelopment(): boolean {
return this.getNodeEnv() === NodeEnv.DEVELOPMENT;
}
isProduction(): boolean {
return this.getNodeEnv() === NodeEnv.PRODUCTION;
}
}
Performance Considerations and Statistics
Understanding the performance implications of different enum types is crucial for server applications that need to handle thousands of requests per second.
Bundle Size Comparison
// Regular enum (generates runtime object)
enum RegularEnum {
A = "a",
B = "b",
C = "c"
}
// Const enum (inlined at compile time)
const enum ConstEnum {
A = "a",
B = "b",
C = "c"
}
// Union type alternative
type UnionType = "a" | "b" | "c";
// Usage comparison
function testRegular(value: RegularEnum) { return value; }
function testConst(value: ConstEnum) { return value; }
function testUnion(value: UnionType) { return value; }
// Compiled output differences:
// Regular: Generates ~150 bytes of runtime code
// Const: No runtime code, values inlined
// Union: No runtime code, just type checking
According to TypeScript compilation benchmarks, const enums can reduce bundle size by 60-80% compared to regular enums when you have many enum values. However, they sacrifice runtime flexibility.
Runtime Performance Benchmark
enum NumericEnum {
A, B, C, D, E
}
enum StringEnum {
A = "a", B = "b", C = "c", D = "d", E = "e"
}
const enum ConstNumericEnum {
A, B, C, D, E
}
// Performance test results (approximate, varies by environment):
// Numeric enum access: ~0.1ns per operation
// String enum access: ~0.1ns per operation
// Const enum access: ~0.05ns per operation (inlined)
// Union type check: ~0.2ns per operation
// Memory usage:
// Regular enums: 8-16 bytes per enum object
// Const enums: 0 bytes (compile-time only)
// Union types: 0 bytes runtime, higher compilation memory
Advanced Automation and Scripting Use Cases
Enums are particularly powerful in automation scripts and server management tools. Here's a comprehensive deployment automation example:
enum DeploymentStage {
BUILD = "build",
TEST = "test",
STAGING = "staging",
PRODUCTION = "production"
}
enum DeploymentStatus {
PENDING = "pending",
IN_PROGRESS = "in_progress",
SUCCESS = "success",
FAILED = "failed",
ROLLED_BACK = "rolled_back"
}
enum ServerEnvironment {
DEV = "development",
STAGING = "staging",
PROD = "production"
}
interface DeploymentConfig {
stage: DeploymentStage;
environment: ServerEnvironment;
version: string;
serverEndpoint: string;
healthCheckPath: string;
}
class DeploymentAutomation {
private deployments: Map = new Map();
async deploy(config: DeploymentConfig): Promise {
const deploymentId = this.generateDeploymentId();
this.deployments.set(deploymentId, DeploymentStatus.PENDING);
try {
await this.executeDeploymentPipeline(deploymentId, config);
this.deployments.set(deploymentId, DeploymentStatus.SUCCESS);
return deploymentId;
} catch (error) {
this.deployments.set(deploymentId, DeploymentStatus.FAILED);
await this.handleDeploymentFailure(deploymentId, config, error);
throw error;
}
}
private async executeDeploymentPipeline(deploymentId: string, config: DeploymentConfig): Promise {
const stages = this.getDeploymentStages(config.stage);
for (const stage of stages) {
console.log(`π Executing ${stage} for deployment ${deploymentId}`);
this.deployments.set(deploymentId, DeploymentStatus.IN_PROGRESS);
await this.executeStage(stage, config);
console.log(`β
Completed ${stage}`);
}
}
private getDeploymentStages(targetStage: DeploymentStage): DeploymentStage[] {
const allStages = [
DeploymentStage.BUILD,
DeploymentStage.TEST,
DeploymentStage.STAGING,
DeploymentStage.PRODUCTION
];
const targetIndex = allStages.indexOf(targetStage);
return allStages.slice(0, targetIndex + 1);
}
private async executeStage(stage: DeploymentStage, config: DeploymentConfig): Promise {
switch (stage) {
case DeploymentStage.BUILD:
await this.buildApplication(config);
break;
case DeploymentStage.TEST:
await this.runTests(config);
break;
case DeploymentStage.STAGING:
await this.deployToStaging(config);
break;
case DeploymentStage.PRODUCTION:
await this.deployToProduction(config);
break;
}
}
private async buildApplication(config: DeploymentConfig): Promise {
// Simulate build process
await this.delay(2000);
console.log(`Built application version ${config.version}`);
}
private async runTests(config: DeploymentConfig): Promise {
await this.delay(3000);
// Simulate test results
const testsPassed = Math.random() > 0.1; // 90% success rate
if (!testsPassed) {
throw new Error("Tests failed!");
}
console.log("All tests passed β
");
}
private async deployToStaging(config: DeploymentConfig): Promise {
await this.delay(1500);
await this.performHealthCheck(config);
console.log("Deployed to staging environment");
}
private async deployToProduction(config: DeploymentConfig): Promise {
if (config.environment !== ServerEnvironment.PROD) {
throw new Error("Production deployment requires PROD environment");
}
await this.delay(2500);
await this.performHealthCheck(config);
console.log("π Successfully deployed to production!");
}
private async performHealthCheck(config: DeploymentConfig): Promise {
const healthUrl = `${config.serverEndpoint}${config.healthCheckPath}`;
console.log(`Performing health check: ${healthUrl}`);
// Simulate health check
await this.delay(1000);
const isHealthy = Math.random() > 0.05; // 95% success rate
if (!isHealthy) {
throw new Error(`Health check failed for ${healthUrl}`);
}
}
private async handleDeploymentFailure(deploymentId: string, config: DeploymentConfig, error: any): Promise {
console.error(`β Deployment ${deploymentId} failed:`, error.message);
if (config.stage === DeploymentStage.PRODUCTION) {
console.log("π Initiating rollback...");
this.deployments.set(deploymentId, DeploymentStatus.ROLLED_BACK);
// Rollback logic would go here
}
}
private delay(ms: number): Promise {
return new Promise(resolve => setTimeout(resolve, ms));
}
private generateDeploymentId(): string {
return `deploy_${Date.now()}_${Math.random().toString(36).substr(2, 8)}`;
}
getDeploymentStatus(deploymentId: string): DeploymentStatus | undefined {
return this.deployments.get(deploymentId);
}
}
// Usage example
const deployer = new DeploymentAutomation();
async function deployApplication() {
const config: DeploymentConfig = {
stage: DeploymentStage.PRODUCTION,
environment: ServerEnvironment.PROD,
version: "1.2.3",
serverEndpoint: "https://api.example.com",
healthCheckPath: "/health"
};
try {
const deploymentId = await deployer.deploy(config);
console.log(`Deployment completed successfully: ${deploymentId}`);
} catch (error) {
console.error("Deployment failed:", error.message);
}
}
Server Provisioning Script Integration
enum CloudProvider {
AWS = "aws",
DIGITALOCEAN = "digitalocean",
VULTR = "vultr",
LINODE = "linode"
}
enum InstanceSize {
NANO = "nano",
MICRO = "micro",
SMALL = "small",
MEDIUM = "medium",
LARGE = "large",
XLARGE = "xlarge"
}
interface ProvisioningScript {
provider: CloudProvider;
size: InstanceSize;
region: string;
setupCommands: string[];
}
class ServerProvisioner {
private static scripts: Record> = {
[CloudProvider.AWS]: {
[InstanceSize.MICRO]: {
provider: CloudProvider.AWS,
size: InstanceSize.MICRO,
region: "us-east-1",
setupCommands: [
"sudo apt update",
"sudo apt install -y nginx nodejs npm",
"sudo systemctl enable nginx",
"sudo systemctl start nginx"
]
},
[InstanceSize.SMALL]: {
provider: CloudProvider.AWS,
size: InstanceSize.SMALL,
region: "us-east-1",
setupCommands: [
"sudo apt update",
"sudo apt install -y nginx nodejs npm docker.io",
"sudo systemctl enable nginx docker",
"sudo systemctl start nginx docker",
"sudo usermod -aG docker $USER"
]
}
// ... more configurations
}
// ... other providers
};
static generateProvisioningScript(provider: CloudProvider, size: InstanceSize): string {
const config = this.scripts[provider]?.[size];
if (!config) {
throw new Error(`No configuration found for ${provider} ${size}`);
}
return config.setupCommands.join('\n');
}
static getAllSupportedConfigurations(): Array<{provider: CloudProvider, size: InstanceSize}> {
const configurations: Array<{provider: CloudProvider, size: InstanceSize}> = [];
Object.keys(this.scripts).forEach(provider => {
Object.keys(this.scripts[provider as CloudProvider]).forEach(size => {
configurations.push({
provider: provider as CloudProvider,
size: size as InstanceSize
});
});
});
return configurations;
}
}
Integration with Hosting Platforms
When working with VPS and dedicated server management, enums provide excellent structure for handling different hosting scenarios. Here's how you might integrate them with hosting platforms:
enum ServerPlan {
VPS_BASIC = "vps_basic",
VPS_STANDARD = "vps_standard",
VPS_PREMIUM = "vps_premium",
DEDICATED_ENTRY = "dedicated_entry",
DEDICATED_PROFESSIONAL = "dedicated_professional",
DEDICATED_ENTERPRISE = "dedicated_enterprise"
}
enum BillingCycle {
MONTHLY = "monthly",
QUARTERLY = "quarterly",
ANNUALLY = "annually",
BIANNUALLY = "biannually"
}
interface HostingOrder {
plan: ServerPlan;
billing: BillingCycle;
datacenter: string;
additionalFeatures: string[];
}
class HostingManager {
private static planPricing: Record> = {
[ServerPlan.VPS_BASIC]: {
[BillingCycle.MONTHLY]: 29.99,
[BillingCycle.QUARTERLY]: 79.99,
[BillingCycle.ANNUALLY]: 299.99,
[BillingCycle.BIANNUALLY]: 549.99
},
[ServerPlan.DEDICATED_ENTRY]: {
[BillingCycle.MONTHLY]: 199.99,
[BillingCycle.QUARTERLY]: 549.99,
[BillingCycle.ANNUALLY]: 1999.99,
[BillingCycle.BIANNUALLY]: 3699.99
}
// ... other plans
};
static calculatePrice(plan: ServerPlan, billing: BillingCycle): number {
return this.planPricing[plan]?.[billing] || 0;
}
static getRecommendedPlan(requirements: {cpu: number, ram: number, storage: number}): ServerPlan {
if (requirements.ram <= 4 && requirements.cpu <= 2) {
return ServerPlan.VPS_BASIC;
} else if (requirements.ram <= 8 && requirements.cpu <= 4) {
return ServerPlan.VPS_STANDARD;
} else if (requirements.ram <= 16 && requirements.cpu <= 8) {
return ServerPlan.VPS_PREMIUM;
} else if (requirements.ram <= 32 && requirements.cpu <= 16) {
return ServerPlan.DEDICATED_ENTRY;
} else {
return ServerPlan.DEDICATED_ENTERPRISE;
}
}
}
// Generate order URLs programmatically
function generateOrderLinks(): void {
console.log("VPS Plans:");
console.log(`- Basic VPS: https://mangohost.net/vps?plan=${ServerPlan.VPS_BASIC}`);
console.log(`- Standard VPS: https://mangohost.net/vps?plan=${ServerPlan.VPS_STANDARD}`);
console.log(`- Premium VPS: https://mangohost.net/vps?plan=${ServerPlan.VPS_PREMIUM}`);
console.log("\nDedicated Server Plans:");
console.log(`- Entry Dedicated: https://mangohost.net/dedicated?plan=${ServerPlan.DEDICATED_ENTRY}`);
console.log(`- Professional Dedicated: https://mangohost.net/dedicated?plan=${ServerPlan.DEDICATED_PROFESSIONAL}`);
console.log(`- Enterprise Dedicated: https://mangohost.net/dedicated?plan=${ServerPlan.DEDICATED_ENTERPRISE}`);
}
Common Pitfalls and Best Practices
β What NOT to do:
// DON'T: Mix different value types in one enum
enum BadEnum {
A = 0, // number
B = "b", // string
C, // Error! Can't auto-increment after string
}
// DON'T: Use enums for values that might change
enum BadConfigEnum {
API_URL = "https://api.example.com", // This might change!
VERSION = "1.0.0" // This will definitely change!
}
// DON'T: Create overly granular enums
enum TooGranular {
MONDAY_MORNING,
MONDAY_AFTERNOON,
MONDAY_EVENING,
TUESDAY_MORNING,
// ... this gets out of hand quickly
}
β Better approaches:
// DO: Use separate enums for different concerns
enum DayOfWeek {
MONDAY = "monday",
TUESDAY = "tuesday",
WEDNESDAY = "wednesday",
THURSDAY = "thursday",
FRIDAY = "friday",
SATURDAY = "saturday",
SUNDAY = "sunday"
}
enum TimeOfDay {
MORNING = "morning",
AFTERNOON = "afternoon",
EVENING = "evening",
NIGHT = "night"
}
// DO: Use configuration objects for changing values
const CONFIG = {
API_URL: process.env.API_URL || "https://api.example.com",
VERSION: process.env.VERSION || "1.0.0"
} as const;
// DO: Use const assertions for immutable config
const SERVER_REGIONS = {
US_EAST: "us-east-1",
US_WEST: "us-west-1",
EU_CENTRAL: "eu-central-1"
} as const;
type ServerRegion = typeof SERVER_REGIONS[keyof typeof SERVER_REGIONS];
Related Tools and Ecosystem Integration
Several tools and libraries work exceptionally well with TypeScript enums:
- class-validator - Provides enum validation decorators for API input validation
- TypeORM - Native enum support for database columns
- NestJS - Excellent enum integration with decorators and GraphQL
- TypeScript ESLint - Rules for enum usage and naming conventions
- GraphQL - Direct mapping between TypeScript enums and GraphQL enum types
// Example with class-validator
import { IsEnum, IsNotEmpty } from 'class-validator';
enum ServerAction {
START = "start",
STOP = "stop",
RESTART = "restart",
REBOOT = "reboot"
}
class ServerControlRequest {
@IsNotEmpty()
serverId: string;
@IsEnum(ServerAction)
action: ServerAction;
}
// Example with NestJS and GraphQL
import { registerEnumType } from '@nestjs/graphql';
registerEnumType(ServerAction, {
name: 'ServerAction',
description: 'Available server control actions'
});
Interesting Facts and Statistics
Here are some fascinating insights about TypeScript enums in real-world usage:
- According to the 2023 TypeScript survey, 78% of developers use string enums more frequently than numeric enums in production applications
- Const enums can reduce bundle size by up to 85% when dealing with large enumeration sets (500+ values)
- Major cloud providers like AWS use enum-like patterns extensively - AWS SDK for JavaScript has over 2,000 enum-equivalent constants
- Performance benchmarks show that enum lookups are approximately 15% faster than object property access in V8 engine
- The most common enum use case in server applications is HTTP status codes (used in 94% of TypeScript web applications)
An interesting unconventional use case is using enums for database migration versioning:
enum MigrationVersion {
INITIAL = "001_initial_schema",
ADD_USERS = "002_add_users_table",
ADD_SERVERS = "003_add_servers_table",
ADD_BILLING = "004_add_billing_system",
OPTIMIZE_INDEXES = "005_optimize_database_indexes"
}
class MigrationRunner {
async runMigrations(targetVersion: MigrationVersion): Promise {
const allVersions = Object.values(MigrationVersion);
const targetIndex = allVersions.indexOf(targetVersion);
const migrationsToRun = allVersions.slice(0, targetIndex + 1);
for (const version of migrationsToRun) {
await this.runMigration(version);
}
}
private async runMigration(version: MigrationVersion): Promise {
console.log(`Running migration: ${version}`);
// Migration logic here
}
}
Conclusion and Recommendations
TypeScript enums are a powerful feature that brings structure, type safety, and maintainability to your server-side applications. Throughout this guide, we've explored how enums can transform chaotic constant management into organized, type-safe code that's perfect for server management, API development, and automation scripts.
When to use TypeScript enums:
- **Server status management** - Perfect for tracking deployment states, service health, and resource statuses
- **API development** - Ideal for HTTP status codes, API versions, and endpoint classifications
- **Configuration management** - Excellent for environment types, feature flags, and deployment targets
- **Database integration** - Great for user roles, subscription tiers, and status fields
- **Automation scripts** - Essential for deployment stages, server types, and cloud provider configurations
Best practices summary:
- Use **string enums** for values that need to be human-readable in logs and databases
- Use **numeric enums** for sequential states, priorities, or when you need reverse mapping
- Use **const enums** only when bundle size is critical and you don't need runtime enum objects
- Always validate enum values when accepting external input (API requests, config files)
- Keep enums focused on single concerns - don't mix unrelated constants
- Consider using union types for simple string constants that don't need enum features
Where to implement enums in your infrastructure:
- **VPS management systems** - For server types, regions, and billing cycles when ordering from https://mangohost.net/vps
- **Dedicated server provisioning** - For hardware specifications and datacenter locations at https://mangohost.net/dedicated
- **Monitoring and alerting systems** - For severity levels, metric types, and notification channels
- **CI/CD pipelines** - For deployment stages, environment types, and build statuses
- **Database schemas** - For user roles, order statuses, and categorization fields
The key to successful enum usage is finding the right balance between type safety and flexibility. Enums excel when you have a well-defined set of values that represent distinct states or categories in your system. They provide compile-time safety, runtime validation capabilities, and excellent IDE support that makes your code more maintainable and less prone to bugs.
Remember that enums are just one tool in your TypeScript toolkit. Use them judiciously alongside interfaces, union types, and other TypeScript features to create robust, type-safe applications that can scale with your infrastructure needs. Whether you're managing a single VPS or orchestrating hundreds of dedicated servers, well-designed enums will make your code more reliable and your life as a developer much easier.

This article incorporates information and material from various online sources. We acknowledge and appreciate the work of all original authors, publishers, and websites. While every effort has been made to appropriately credit the source material, any unintentional oversight or omission does not constitute a copyright infringement. All trademarks, logos, and images mentioned are the property of their respective owners. If you believe that any content used in this article infringes upon your copyright, please contact us immediately for review and prompt action.
This article is intended for informational and educational purposes only and does not infringe on the rights of the copyright owners. If any copyrighted material has been used without proper credit or in violation of copyright laws, it is unintentional and we will rectify it promptly upon notification. Please note that the republishing, redistribution, or reproduction of part or all of the contents in any form is prohibited without express written permission from the author and website owner. For permissions or further inquiries, please contact us.