TypeScript Enums: 5 Real-World Use Cases

Alex - Mar 12 - - Dev Community

If you’re looking to make your TypeScript code more organized, enums are a powerful tool. They group related values together, giving your code better structure and readability. Let’s dive in and explore how to use them!

In TypeScript, enums are declared using the enum keyword. For example, you could create an enum to represent the different fruit prices as follows:

Example 1: Basic Enum Structure — Key Movements

Demonstrates a common use case for enums: making choices within a limited set clearer.

enum Movement {
  Up = "UP",
  Down = "DOWN",
  Left = "LEFT",
  Right = "RIGHT"
}

function handlePlayerInput(key: string) {
  switch (key) {
    case Movement.Up:
     // Move player character up
      break;
    case Movement.Down:
      // Move player character down
      break;
    // ... other cases
  }
}
Enter fullscreen mode Exit fullscreen mode

This demonstrates the fundamental syntax for defining an enum. The Movement enum has four members representing directions.

Example 2: Enums with Values

Enums can have associated values (numbers, strings, etc.). Here, StatusCode associates HTTP status codes, ensuring type-safety and preventing the use of arbitrary numbers.

enum StatusCode {
  OK = 200,
  BadRequest = 400,
  NotFound = 404
}

function handleResponse(code: StatusCode) {
  if (code === StatusCode.OK) {
    // Handle successful response
  } else if (code === StatusCode.NotFound) {
    // Handle resource not found
  } 
  // ... other cases
}
Enter fullscreen mode Exit fullscreen mode

HTTP status codes

Image source: https://restfulapi.net/http-status-codes

Example 3: Enum from Redux Toolkit

Redux Toolkit is a popular library for state management in React applications. It makes heavy use of TypeScript for type safety.

Redux logo

This enum defines distinct states for asynchronous actions (like fetching data). This is common in state management libraries.

enum PayloadActionLoadingState {
  Idle = "idle",
  Loading = "loading",
  Failed = "failed",
  Success = "success" 
}
Enter fullscreen mode Exit fullscreen mode

Example 4: Enum as a Discriminated Union

This enum defines two possible shapes: Circle and Rectangle. It acts as a foundation for ensuring type safety when working with different shapes.

Each shape type (Circle, Rectangle) is represented as a member of the ShapeType enum.

The Shape interface has a type property that must be a member of the ShapeType enum.

enum ShapeType {
    Circle = "Circle",
    Rectangle = "Rectangle"
  }

  interface Shape {
    type: ShapeType; 
  }

  interface Circle extends Shape {
    type: ShapeType.Circle;
    radius: number;
  }

  interface Rectangle extends Shape {
    type: ShapeType.Rectangle;
    width: number;
    height: number;
  }

  function calculateArea(shape: Shape): number {
    switch (shape.type) {
      case ShapeType.Circle:
        const circle = shape as Circle; // Type assertion to Circle
        return Math.PI * circle.radius * circle.radius;
      case ShapeType.Rectangle:
        const rectangle = shape as Rectangle; // Type assertion to Rectangle
        return rectangle.width * rectangle.height;
      default:
        throw new Error("Invalid shape type");
    }
  }
Enter fullscreen mode Exit fullscreen mode

Specific shape interfaces (Circle, Rectangle) extend the base Shape interface and must have their type property set to the corresponding enum value.

This lets the calculateArea function use the type property as a discriminator to determine the appropriate calculation.

Example 5: Enums as Data Structures

This TypeScript code defines a simple model for representing playing cards, focusing on the suits, ranks, and the color of the card, which is derived from its suit.

It consists of two enums, a function to get a card’s numerical value, an interface to describe a card’s structure, and a function to create a card.

enum Suit {
  Hearts = "", // Red suit
  Diamonds = "", // Red suit
  Clubs = "", // Black suit
  Spades = "" // Black suit
}

enum Rank {
  Ace = 1,
  Two, Three, Four, Five, Six, Seven, Eight, Nine, Ten,
  Jack, Queen, King 
}

function getCardValue(rank: Rank): number {
  if (rank <= Rank.Ten) {
    return rank;
  } else {
    return 10;
  }
}

interface Card {
  suit: Suit;
  rank: Rank;
  color: string; // Derived property based on suit
}

function createCard(suit: Suit, rank: Rank): Card {
  return {
    suit,
    rank,
    color: suit === Suit.Hearts || suit === Suit.Diamonds ? 'Red' : 'Black'
  }
}

// Usage
let card1 = createCard(Suit.Hearts, Rank.Ace);
console.log(`The Ace of Hearts is red: ${card1.color}`); // Output: The Ace of Hearts is red: Red

let card2 = createCard(Suit.Spades, Rank.Queen);
console.log(`The Queen of Spades is black: ${card2.color}`); // Output: The Queen of Spades is black: Black
Enter fullscreen mode Exit fullscreen mode

Function getCardValue takes a Rank as an argument and returns a number. For ranks Ace through Ten (numerically 1 to 10), it returns the rank's numeric value. For face cards (Jack, Queen, King), which have rank values greater than 10, it returns 10.

Two card objects are created using the createCard function: card1 as the Ace of Hearts (which is red) and card2 as the Queen of Spades (which is black).

This code is a straightforward way to model the basic properties of playing cards in a type-safe manner using TypeScript’s features like enums, interfaces, and type inference.

Conclusion

Enums provide a solid foundation for clean and structured TypeScript code. As your projects grow in complexity, their benefits will continue to shine.

TypeScript enums are a powerful tool to elevate your code. They enhance readability, maintainability, and type safety.

Check out my other TypeScript articles:

This article was originally posted on Medium.

. . . . . . . . . .
Terabox Video Player