How to Avoid Duplicate Enum Values in TypeScript

Avoiding duplicate enum values in TypeScript is important to maintain clarity and avoid unexpected behavior when using enums. Here’s a realistic scenario showing how duplicate values can cause problems and how to avoid them.

In this tutorial, we will learn how to avoid duplicate Enum values in TypeScript, how duplicate enum values can lead to hard-to-track bugs, and how to prevent this issue in your codebase. As your project grows, we’ll explore real-world examples and best practices for managing enums.

Understanding the Duplicate Enum Values Problem in TypeScript

enum Status {
  Success = 1,
  Completed = 1,
  Failed = 2
}

The code defines a Status enum with duplicate numeric values (Success = 1, Completed = 1), causing logical ambiguity.

So what’s the problem? When used in a switch statement, the value 1 always resolves to the first matching case, making the Completed case unreachable. This leads to incorrect status messages being returned and introduces bugs that are hard to trace.

function getStatusMessage(status: Status): string {
  switch (status) {
    case Status.Success:
      return "Operation was successful.";
    case Status.Completed:
      return "Operation completed.";
    case Status.Failed:
      return "Operation failed.";
    default:
      return "Unknown status.";
  }
}

console.log(getStatusMessage(Status.Completed));  //  Outputs: "Operation was successful."

Even though Completed and Success are two different names, they both have the value 1, so the switch will always match the first case (Success). This can lead to unexpected or incorrect behavior.

Duplicate Enum Values Problem in TypeScript

Avoid Duplicate Enum Values in TypeScript

So, how can we prevent this issue? One approach is to use TypeScript’s unique symbol:

// Declare each status as a constant unique symbol
const success = Symbol('Success');
const completed = Symbol('Completed');
const failed = Symbol('Failed');

// Create the Status object
const Status = {
  Success: success,
  Completed: completed,
  Failed: failed,
} as const;

// Create a type that includes only these values
type Status = typeof Status[keyof typeof Status];

function getStatusMessage(status: Status): string {
  switch (status) {
    case Status.Success:
      return "Operation was successful.";
    case Status.Completed:
      return "Operation completed.";
    case Status.Failed:
      return "Operation failed.";
    default:
      return "Unknown status.";
  }
}

// Usage
console.log(getStatusMessage(Status.Completed)); // "Operation completed."

By using the unique symbol, we ensure each enum value is distinct, even if they have the same string representation. If we try to add a duplicate value, TypeScript will throw an error.

While this doesn’t prevent duplicate values, it makes them more explicit and less likely to happen accidentally.

Avoid Duplicate Enum Values in TypeScript

Best Practices for Managing Enums

As your project grows, enums can become difficult to manage. Here are some tips:

  1. Keep enums focused and specific. Don’t try to represent too many things in one enum.
  2. Use descriptive names for your enums and their values. Avoid abbreviations when possible.
  3. Consider organizing related enums into separate files or namespaces.
  4. If an enum becomes too large, consider refactoring it into a more manageable structure, such as an object or interface.
  5. Use comments to clarify the purpose and usage of your enums.

Following these practices allows you to keep your enums readable and maintainable even as your codebase expands.

Real-World Avoid Duplicate Enum in TypeScript Example

Let’s look at a more complex example. Imagine you’re building an e-commerce site that needs to calculate sales tax based on the customer’s state and product category:

enum States {
  California = 'CA',
  Texas = 'TX',
  Florida = 'FL',
  NewYork = 'NY'
}

enum ProductCategory {
  Electronics = 'electronics',
  Clothing = 'clothing',
  Food = 'food'
}

function calculateTax(state: States, category: ProductCategory, price: number): number {
  console.log(`Calculating tax for state: ${state}, category: ${category}, price: $${price}`);

  let taxRate = 0;

  switch (state) {
    case States.California:
      taxRate = category === ProductCategory.Food ? 0 : 0.0725;
      break;
    case States.Texas:
      taxRate = category === ProductCategory.Food ? 0 : 0.0625;
      break;
    case States.Florida:
      taxRate = category === ProductCategory.Food ? 0 : 0.06;
      break;
    case States.NewYork:
      taxRate = category === ProductCategory.Food ? 0 : 0.04;
      break;
    default:
      throw new Error('Unsupported state');
  }

  const taxAmount = price * taxRate;
  console.log(`Tax rate: ${taxRate * 100}%, Tax amount: $${taxAmount.toFixed(2)}`);

  return taxAmount;
}

// Example usage
console.log('Total tax:', calculateTax(States.California, ProductCategory.Electronics, 100));

In this example, we use two enums (States and ProductCategory) to make our tax calculation logic more readable and less error-prone. Using enums, we avoid magic strings and clarify what values are allowed.

Real-World Avoid Duplicate Enum in TypeScript Example

Conclusion

Duplicate enum values in TypeScript can lead to subtle bugs that are hard to track down. Understanding the problem and using techniques like unique symbols or string enums can prevent these issues and make our code more maintainable.

Additionally, by following best practices for managing enums, like keeping them focused and using descriptive names, we can ensure our enums remain a useful tool even as our project grows.

You may like to read:

51 Python Programs

51 PYTHON PROGRAMS PDF FREE

Download a FREE PDF (112 Pages) Containing 51 Useful Python Programs.

pyython developer roadmap

Aspiring to be a Python developer?

Download a FREE PDF on how to become a Python developer.

Let’s be friends

Be the first to know about sales and special discounts.