Enums

1. Welcome and Icebreaker:

  • Hello! What’s a real-world set of related constants you can think of (e.g., days of the week, traffic light colors)?

2. Outline the Session:

  • Today we’re learning about Enums (enumerations) in TypeScript.
  • We’ll cover: what enums are, numeric enums, string enums, and their use cases.
  • Learning Outcomes: You’ll be able to define and use enums to create sets of named constants.
  • Let’s get started!

3. Concept Explanation:

  • Enums (short for enumerations) allow us to define a set of named constants. Using enums can make it easier to document intent, or create a set of distinct cases.

  • TypeScript provides both numeric and string-based enums.

  • Numeric Enums:

    • By default, enums are number-based. The first value is initialized to 0, and each subsequent value is auto-incremented by 1.
    • You can also manually set the value for members.
  • String Enums:

    • In a string enum, each member has to be constant-initialized with a string literal, or with another string enum member.
    • String enums don’t have auto-incrementing behavior, so each member needs to be explicitly assigned a string value.
    • They offer better readability when debugging, as the string value is often more descriptive than a number.
  • Use Cases:

    • Representing states (e.g., OrderStatus.Pending, OrderStatus.Shipped).
    • Directions (e.g., Direction.Up, Direction.Down).
    • Log levels (e.g., LogLevel.Error, LogLevel.Warning, LogLevel.Info).
    • Any scenario where you have a fixed set of related constants.

4. Live Coding Demonstration:

// Numeric Enums
console.log("--- Numeric Enums ---");
enum Direction {
  Up,    // 0 by default
  Down,  // 1
  Left,  // 2
  Right  // 3
}

let myDirection: Direction = Direction.Up;
console.log("My direction (value):", myDirection); // Outputs: 0
console.log("My direction (name):", Direction[myDirection]); // Outputs: Up

enum ResponseStatus {
  Success = 200,
  NotFound = 404,
  Error = 500
}

let apiStatus: ResponseStatus = ResponseStatus.NotFound;
console.log("API Status (value):", apiStatus); // Outputs: 404
console.log("API Status (name):", ResponseStatus[apiStatus]); // Outputs: NotFound

// You can also get the value from the name
console.log("Direction.Left value:", Direction.Left); // Outputs: 2

// String Enums
console.log("\n--- String Enums ---");
enum LogLevel {
  INFO = "INFO",
  WARNING = "WARN",
  ERROR = "ERROR",
  DEBUG = "DEBUG"
}

let appLogLevel: LogLevel = LogLevel.WARNING;
console.log("App Log Level:", appLogLevel); // Outputs: WARN
// console.log(LogLevel["WARN"]); // This reverse mapping doesn't exist for string enums

// Using enums in a function
function respond(status: ResponseStatus): void {
  switch (status) {
    case ResponseStatus.Success:
      console.log("Operation was successful (200).");
      break;
    case ResponseStatus.NotFound:
      console.log("Resource not found (404).");
      break;
    case ResponseStatus.Error:
      console.log("An error occurred (500).");
      break;
    default:
      // Handle other cases or throw an error
      const exhaustiveCheck: never = status; // Ensures all cases are handled
      console.log("Unknown status:", exhaustiveCheck);
  }
}

respond(ResponseStatus.Success);
respond(apiStatus); // apiStatus is ResponseStatus.NotFound

// Heterogeneous Enums (Numeric and String members - generally not recommended due to potential confusion)
console.log("\n--- Heterogeneous Enums ---");
enum MixedBag {
  Yes = 1,
  No = "NO",
  // Maybe // Error if not initialized, as previous member was string
}
console.log("MixedBag.Yes:", MixedBag.Yes); // 1
console.log("MixedBag.No:", MixedBag.No); // NO

// Const Enums
// Const enums are completely removed during compilation and their values are inlined.
// This can lead to performance benefits.
// They cannot have computed members.
console.log(
  "\n--- Const Enums (Example, not runnable directly like this in all environments without transpilation details) ---"
);
const enum FileAccess {
  Read = 1,
  Write = 2,
  ReadWrite = Read | Write, // Computed member example (bitwise OR)
}

// let readFile: FileAccess = FileAccess.Read;
// console.log("Read access:", readFile); // In compiled JS, this would be console.log("Read access:", 1);

5. Tasks:

  • Short Exercise:
    1. Create a numeric enum Weekday for the days of the week (Sunday, Monday, …, Saturday). Let Sunday be 0.
    2. Print the numeric value of Wednesday.
    3. Create a string enum OrderStatus with the following members: Pending, Shipped, Delivered, Cancelled. Assign appropriate string values to them (e.g., PENDING, SHIPPED).
    4. Declare a variable currentOrder of type OrderStatus and assign it the Shipped status. Print its value.
    5. Write a function getDiscount(day: Weekday): string that returns “10% off” if the day is Saturday or Sunday, and “No discount today” otherwise. Test it with a weekday.