TypeScript Enum vs Const: Which One Should You Choose?

Recently, I was working on a large TypeScript project where I needed to create a set of related constants for user roles. The question that I faced was whether to use an enum or a const object. After years of experience with TypeScript, I’ve developed strong opinions about when to use each approach.

In this article, I’ll share my insights on TypeScript enums vs const objects, explaining the pros and cons of each. I’ll provide practical examples to help you make the right choice for your own projects. So let’s dive in!

What Are TypeScript Enums?

Enums in TypeScript allow you to define a set of named constants. They’re a way to organize related values that won’t change during the execution of your program.

Here’s a basic example of a TypeScript enum:

enum UserRole {
  Admin = 'ADMIN',
  Editor = 'EDITOR',
  Viewer = 'VIEWER'
}

function checkAccess(role: UserRole) {
  if (role === UserRole.Admin) {
    console.log('Full access granted');
  }
}

checkAccess(UserRole.Admin); // Works
checkAccess('ADMIN'); // Error: Argument of type 'string' is not assignable to parameter of type 'UserRole'

You can see the exact output in the screenshot below:

typescript enum vs const

Check out TypeScript Enum vs Union Type

What Are Const Objects/Arrays?

An alternative approach is using const objects or arrays with the as const assertion:

const UserRole = {
  Admin: 'ADMIN',
  Editor: 'EDITOR',
  Viewer: 'VIEWER'
} as const;

type UserRoleType = typeof UserRole[keyof typeof UserRole];

function checkAccess(role: UserRoleType) {
  if (role === UserRole.Admin) {
    console.log('Full access granted');
  }
}

checkAccess(UserRole.Admin); // Works
checkAccess('ADMIN'); // Error: Argument of type 'string' is not assignable to parameter of type 'UserRoleType'

Read Get Key by Value from enum String in Typescript

Enum vs Const: Side-by-Side Comparison

Let’s compare the key differences between enums and const objects in TypeScript:

FeatureTypeScript EnumConst Objects/Arrays
Runtime OverheadGenerates JavaScript code at runtimeZero runtime overhead when used with as const
Tree-ShakingNot tree-shakable by defaultFully compatible with tree-shaking
Type SafetyBuilt-in type safetyRequires as const assertion for full type safety
Reverse MappingAvailable for numeric enumsNot available natively
ExtensibilityFixed after declarationCan be composed and extended
Bundle SizeLarger bundle sizeSmaller bundle size
Usage in UnionsCan be awkward in discriminated unionsWorks well with discriminated unions
FlexibilityLess flexibleMore flexible with TypeScript’s type system

Check out How to Iterate Over Enums in TypeScript?

Numeric Enums vs String Enums vs Const Objects

Let me show you how numeric and string enums work and the differences with const objects.

Numeric Enums

Numeric enums in TypeScript assign numeric values by default and offer reverse mapping:

enum HttpStatusCode {
  OK = 200,
  BadRequest = 400,
  Unauthorized = 401,
  NotFound = 404
}

console.log(HttpStatusCode.NotFound); // 404
console.log(HttpStatusCode[404]); // "NotFound" (reverse mapping)

String Enums

String enums are more readable and explicit:

enum PaymentMethod {
  CreditCard = 'CREDIT_CARD',
  BankTransfer = 'BANK_TRANSFER',
  PayPal = 'PAYPAL'
}

console.log(PaymentMethod.CreditCard); // "CREDIT_CARD"

Const Objects with as const

Const objects with as const provide type safety with no runtime overhead:

const USState = {
  Alabama: 'AL',
  Alaska: 'AK',
  Arizona: 'AZ',
  California: 'CA',
  NewYork: 'NY',
  Texas: 'TX'
} as const;

type StateCode = typeof USState[keyof typeof USState];

Check out Convert String to Enum in TypeScript

Key Differences in Code Generation

One of the most significant differences between enums and const objects is what happens in the compiled JavaScript. Let’s look at how each gets compiled:

Compiled Enum Code

// TypeScript
enum Direction {
  Up = "UP",
  Down = "DOWN",
  Left = "LEFT",
  Right = "RIGHT"
}

// Compiled JavaScript
var Direction;
(function (Direction) {
    Direction["Up"] = "UP";
    Direction["Down"] = "DOWN";
    Direction["Left"] = "LEFT";
    Direction["Right"] = "RIGHT";
})(Direction || (Direction = {}));

Compiled Const Object Code

// TypeScript
const Direction = {
  Up: "UP",
  Down: "DOWN",
  Left: "LEFT",
  Right: "RIGHT"
} as const;

// Compiled JavaScript
const Direction = {
  Up: "UP",
  Down: "DOWN",
  Left: "LEFT",
  Right: "RIGHT"
};

As you can see, the enum generates more JavaScript code, which increases bundle size.

Check out TypeScript Enum Naming Conventions

Tree-Shaking Benefits with Const

Tree-shaking is a crucial optimization technique in modern web development. Let’s see how const objects excel in this area:

// With const objects
const ProductCategory = {
  Electronics: 'electronics',
  Clothing: 'clothing',
  Books: 'books',
  HomeAndKitchen: 'home-and-kitchen',
  Toys: 'toys'
} as const;

// If you only use Electronics category in a module
export function getElectronicsDiscount(price: number) {
  return price * 0.9; // 10% off electronics
  // Only ProductCategory.Electronics is kept after tree-shaking
}

With enums, the entire enum object would be included in the bundle.

Check out Check If a String Is in an Enum in TypeScript

Using Enums and Const Objects with Discriminated Unions

Discriminated unions are a powerful TypeScript pattern. Here’s how enums and const objects work with them:

With Enums

enum ShapeType {
  Circle = 'circle',
  Square = 'square',
  Triangle = 'triangle'
}

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

interface Square {
  type: ShapeType.Square;
  sideLength: number;
}

type Shape = Circle | Square;

function getArea(shape: Shape): number {
  switch (shape.type) {
    case ShapeType.Circle:
      return Math.PI * shape.radius ** 2;
    case ShapeType.Square:
      return shape.sideLength ** 2;
  }
}

With Const Objects

const ShapeType = {
  Circle: 'circle',
  Square: 'square',
  Triangle: 'triangle'
} as const;

type ShapeTypeValue = typeof ShapeType[keyof typeof ShapeType];

interface Circle {
  type: typeof ShapeType.Circle;
  radius: number;
}

interface Square {
  type: typeof ShapeType.Square;
  sideLength: number;
}

type Shape = Circle | Square;

function getArea(shape: Shape): number {
  switch (shape.type) {
    case ShapeType.Circle:
      return Math.PI * shape.radius ** 2;
    case ShapeType.Square:
      return shape.sideLength ** 2;
  }
}

The const approach is often more flexible when working with complex type systems.

Check out Convert TypeScript Enums to Arrays

Real-World Usage Examples

Now, let me show you some real examples, and you will learn when to use enums and const, etc.

When to Use Enums

Enums are ideal for truly enumerated types with a fixed set of options:

// A good use case for enums
enum DayOfWeek {
  Monday = 1,
  Tuesday = 2,
  Wednesday = 3,
  Thursday = 4,
  Friday = 5,
  Saturday = 6,
  Sunday = 7
}

function isWeekend(day: DayOfWeek): boolean {
  return day === DayOfWeek.Saturday || day === DayOfWeek.Sunday;
}

When to Use Const Objects

Const objects shine when working with values that might be extended or in performance-critical applications:

// A good use case for const objects
const HttpMethod = {
  GET: 'GET',
  POST: 'POST',
  PUT: 'PUT',
  DELETE: 'DELETE',
  PATCH: 'PATCH'
} as const;

type Method = typeof HttpMethod[keyof typeof HttpMethod];

function fetchData(url: string, method: Method) {
  // Implementation
}

fetchData('https://api.example.com/users', HttpMethod.GET);

When to Choose Each Approach

Based on my experience working with TypeScript in various projects, here’s when I recommend using each approach:

Choose Enums When:

  • You need reverse mapping (numeric enums only)
  • You’re working with a fixed set of related constants
  • Readability and intent are more important than bundle size
  • You’re working in a traditional, OOP-style codebase

Choose Const Objects When:

  • Bundle size optimization is important
  • You need better tree-shaking support
  • You’re working with values that might be extended later
  • You need more flexibility with TypeScript’s type system
  • You’re working in a functional programming style
TypeScript Enum vs Const differences

Conclusion

Both TypeScript enums and const objects have their place in modern TypeScript development. The key is understanding their differences clearly.

In this tutorial, I have explained the differences between Enum vs Const in TypeScript.

You may also like:

Power Apps functions free pdf

30 Power Apps Functions

This free guide walks you through the 30 most-used Power Apps functions with real business examples, exact syntax, and results you can see.

Download User registration canvas app

DOWNLOAD USER REGISTRATION POWER APPS CANVAS APP

Download a fully functional Power Apps Canvas App (with Power Automate): User Registration App