Skip to main content

What is an Enum?

An enum (enumeration) is a set of named constants. Instead of using loose strings like "loading", "error", we use predefined values that the editor can verify.

Basic Syntax

enum EnumName {
  Value1 = "VALUE1",
  Value2 = "VALUE2",
  Value3 = "VALUE3"
}

Real Example: Loading States

From our project, we define the 4 possible loading states:
main.ts
enum LoadingState {
  Idle = "IDLE",         // Initial state: nothing done yet
  Loading = "LOADING",   // Loading: waiting for server response
  Success = "SUCCESS",   // Success: data loaded correctly
  Error = "ERROR"        // Error: something went wrong
}

Using the Enum

main.ts
let appState: AppState = {
  status: LoadingState.Idle,  // Access with dot notation
  products: [],
  error: null
};

Why Use Enums Instead of Strings?

Without Enum (Error-Prone)

// ❌ Typo! No error until runtime
if (status === "loadng") { }

// ❌ Case mismatch - hard to catch
if (status === "LOADING") { }  // Did you mean lowercase?
if (status === "loading") { }  // Or uppercase?

With Enum (Safe)

// ✅ Autocompletion helps you
if (status === LoadingState.Loading) { }

// ❌ Immediate error - typo caught instantly!
if (status === LoadingState.Loadng) { }  // Error: Property 'Loadng' does not exist

Advantages of Enums

1. Autocompletion

Your editor suggests all valid values:
appState.status = LoadingState. // Editor shows: Idle, Loading, Success, Error

2. Easy Refactoring

Change a value once, it updates everywhere:
enum LoadingState {
  Idle = "IDLE",
  Loading = "FETCHING",  // Changed from "LOADING" - all usages update!
  Success = "SUCCESS",
  Error = "ERROR"
}

3. Documentation

You can see all possible values in one place:
// What values are valid? Look at the enum!
enum LoadingState {
  Idle = "IDLE",      
  Loading = "LOADING",
  Success = "SUCCESS",
  Error = "ERROR"
}

4. Type Safety

TypeScript prevents you from using invalid values:
appState.status = LoadingState.Success; // ✅ Valid
appState.status = "random-string";      // ❌ Error: Type '"random-string"' is not assignable

Using Enums with Switch Statements

Enums work perfectly with switch statements:
main.ts
switch (appState.status) {
  case LoadingState.Idle:
    // Show initial message
    break;
    
  case LoadingState.Loading:
    // Show loading spinner
    break;
    
  case LoadingState.Success:
    // Render products
    break;
    
  case LoadingState.Error:
    // Show error message
    break;
}
From our actual updateUI function:
main.ts
function updateUI(): void {
  const grid = getElement<HTMLDivElement>("#products-grid");
  const loading = getElement<HTMLDivElement>("#products-loading");
  const error = getElement<HTMLDivElement>("#products-error");
  const loadBtn = getElement<HTMLButtonElement>("#load-products-btn");
  
  loading.hidden = true;
  error.hidden = true;
  
  switch (appState.status) {
    case LoadingState.Idle:
      grid.innerHTML = `<p class="products__empty-state">Click "Load Products" to see the catalog</p>`;
      loadBtn.disabled = false;
      loadBtn.textContent = "Load Products";
      break;
      
    case LoadingState.Loading:
      grid.innerHTML = '';
      loading.hidden = false;
      loadBtn.disabled = true;
      loadBtn.textContent = "Loading...";
      break;
      
    case LoadingState.Success:
      renderProducts();
      loadBtn.disabled = false;
      loadBtn.textContent = "Reload Products";
      break;
      
    case LoadingState.Error:
      grid.innerHTML = '';
      error.hidden = false;
      const errorMessage = error.querySelector(".products__error-message");
      if (errorMessage) {
        errorMessage.textContent = appState.error || "Unknown error";
      }
      loadBtn.disabled = false;
      loadBtn.textContent = "Retry";
      break;
  }
}

String Enums vs Numeric Enums

We use string values for better debugging:
enum LoadingState {
  Idle = "IDLE",
  Loading = "LOADING"
}

console.log(LoadingState.Idle); // Logs: "IDLE" (readable!)

Numeric Enums

TypeScript can also use numbers (less common):
enum Direction {
  Up,      // 0
  Down,    // 1
  Left,    // 2
  Right    // 3
}

console.log(Direction.Up); // Logs: 0 (less readable)

Real-World State Management Flow

Here’s how our enum flows through the app:
// 1. User clicks "Load Products"
async function loadProducts(): Promise<void> {
  // 2. Set state to Loading
  appState.status = LoadingState.Loading;
  updateUI();  // Shows spinner
  
  try {
    // 3. Fetch data
    const products = await fetchProducts(20);
    
    // 4. Success! Set state to Success
    appState.status = LoadingState.Success;
    appState.products = products;
    
  } catch (error) {
    // 5. Error! Set state to Error
    appState.error = error instanceof Error ? error.message : "Unknown error";
    appState.status = LoadingState.Error;
  }
  
  // 6. Update UI based on final state
  updateUI();
}

When to Use Enums

Use enums when you have:
  • Fixed set of options: Loading states, user roles, order statuses
  • Values that won’t change often: HTTP methods, file types
  • Related constants: Colors, sizes, priorities

Good Use Cases

enum UserRole {
  Admin = "ADMIN",
  User = "USER",
  Guest = "GUEST"
}

enum OrderStatus {
  Pending = "PENDING",
  Processing = "PROCESSING",
  Shipped = "SHIPPED",
  Delivered = "DELIVERED",
  Cancelled = "CANCELLED"
}

enum HttpMethod {
  GET = "GET",
  POST = "POST",
  PUT = "PUT",
  DELETE = "DELETE"
}

Debugging with Enums

String enums make console.log output more readable:
console.log("Current status:", appState.status);
// Output: Current status: LOADING
// Not: Current status: 1 (if using numeric enum)

Next Steps

Build docs developers (and LLMs) love