LearnAI ToolsCareerPractice BuildsPlayContact
Lesson 1014 min read

Enums

Learn TypeScript enums: numeric enums, string enums, const enums, and how they compare to literal union types.

Introduction

An enum names a fixed, related set of constant values — like the days of the week, or the status of an order. Unlike almost every other TypeScript type construct, a regular enum is not fully erased: it compiles into a real JavaScript object that exists at runtime.

What You Will Learn
  • How numeric enums auto-increment and support reverse mapping.
  • How string enums differ from numeric enums.
  • What const enums are and their build-tool caveats.
  • How enums compare to literal union types, and which to reach for.
  • When to avoid enums in modern TypeScript codebases.

Numeric Enums

By default, enum members are assigned auto-incrementing numbers starting from 0. Numeric enums also support "reverse mapping" — looking up a member's name from its number.

enum Direction {
Up, // 0
Down, // 1
Left, // 2
Right, // 3
}
let move: Direction = Direction.Up;
console.log(move); // 0
console.log(Direction[0]); // "Up" (reverse mapping)

String Enums

String enums require every member to have an explicit string value, and — unlike numeric enums — do not support reverse mapping. They are generally more debuggable, since logging a string enum value shows something meaningful instead of a bare number.

enum Status {
Active = "ACTIVE",
Inactive = "INACTIVE",
Pending = "PENDING",
}
function describe(status: Status): string {
return `Order is ${status}`;
}
console.log(describe(Status.Active));
Output

Click Run to see what this code prints.

Const Enums

Prefixing an enum with `const` tells the compiler to inline every usage directly at compile time, generating no runtime object at all — a small performance and bundle-size win. The catch: `const enum` requires whole-program type information, so it is not supported by single-file transpilers like Babel or esbuild running with `isolatedModules` enabled, which is common in modern build setups.

const enum LogLevel {
Info,
Warn,
Error,
}
// Compiles to: console.log(1);
console.log(LogLevel.Warn);

Enums vs Literal Unions

AspectEnumLiteral Union
Exists at runtimeYes (except const enum)No — compile-time only
Bundle size impactAdds a small runtime objectZero — fully erased
Interop with plain JS valuesRequires importing the enumAny matching string/number works directly
Build tool compatibilityconst enum can break single-file transpilersAlways compatible

When Not to Use Enums

Because of the tradeoffs above, many modern TypeScript style guides — including large teams at companies with big TypeScript codebases — recommend literal union types over enums for simple, closed sets of string values, reserving actual enums for cases where you specifically want a real, iterable runtime object.

Common Mistakes

Avoid These Mistakes
  • Expecting reverse mapping to work on string enums — it only exists for numeric enums.
  • Inserting a new member in the middle of a numeric enum, silently shifting every subsequent member's numeric value.
  • Enabling `const enum` in a project built with a single-file transpiler (Babel, esbuild, SWC) under isolatedModules, causing build errors.
  • Using an enum where a simple literal union type would have been simpler and added zero runtime cost.

Best Practices

  • Prefer string enums over numeric enums when the value matters for logging or debugging.
  • Consider literal union types instead of enums for simple, closed sets of string values, especially in modern esbuild/SWC/Babel-based build pipelines.
  • Avoid `const enum` unless you fully control the build pipeline and know it's compatible.
  • Never rely on the exact numeric value of a numeric enum member remaining stable across future refactors.

Frequently Asked Questions

Numeric enums auto-increment from an integer (0 by default) and support reverse mapping; string enums require an explicit string value per member and have no reverse mapping.

Yes, unlike almost every other TypeScript type construct — a regular enum compiles into a real JavaScript object. const enum is the exception, since it is inlined and produces no runtime object.

Not necessarily — many modern TypeScript style guides prefer literal union types for simple cases, reserving enums for when a real, iterable runtime object is genuinely useful.

Technically yes ("heterogeneous enums") but it is discouraged and rarely useful in real code.

Key Takeaways

  • Numeric enums auto-increment from 0 by default and support reverse mapping.
  • String enums require explicit values and are more debuggable, but have no reverse mapping.
  • const enum inlines values at compile time with no runtime object, but can break some build tools.
  • Literal union types are a zero-runtime-cost alternative to enums for simple, closed sets of values.
  • Enums are one of the few TypeScript constructs that actually exist in the compiled JavaScript.

Summary

You now understand enums and how they compare to literal union types. Next, you'll learn type narrowing and type guards — how TypeScript proves a value's specific type from the runtime checks you already write.

Next Lesson →

Type Narrowing & Type Guards