# How to Create and Use enum in TypeScript: Complete Guide with Source Code Analysis

> Learn how to create and use enums in TypeScript with our complete guide. Explore enums and const enums with source code analysis for efficient development.

- Repository: [Microsoft/TypeScript](https://github.com/microsoft/typescript)
- Tags: tutorial
- Published: 2026-02-12

---

**TypeScript's `enum` declaration creates both a compile-time type for static checking and a runtime object mapping names to values, with `const enum` providing zero-runtime-cost alternatives through compile-time inlining.**

The `enum in TypeScript` is implemented in the [microsoft/TypeScript](https://github.com/microsoft/TypeScript) repository through a sophisticated compiler pipeline that transforms high-level declarations into optimized JavaScript output. Understanding how the compiler handles these declarations in [`src/compiler/parser.ts`](https://github.com/microsoft/TypeScript/blob/main/src/compiler/parser.ts) and [`src/compiler/emitter.ts`](https://github.com/microsoft/TypeScript/blob/main/src/compiler/emitter.ts) enables developers to choose between standard enums, `const enum` optimizations, or enum-like alternatives based on their specific performance and type-safety requirements.

## How TypeScript Compiles enum Declarations

When the TypeScript compiler encounters an `enum` declaration, it generates two distinct artifacts that serve different purposes in your application.

### The Parse Phase: Creating EnumDeclaration Nodes

In [`src/compiler/parser.ts`](https://github.com/microsoft/TypeScript/blob/main/src/compiler/parser.ts), the `parseEnumDeclaration` function constructs a syntax node of kind `EnumDeclaration` that represents the enum in the abstract syntax tree. This parser handles the full range of enum syntax, from simple numeric sequences to complex string initializers, and stores the member definitions for later type-checking and emission phases.

### The Emit Phase: Generating Runtime Objects

The transformation into JavaScript occurs in [`src/compiler/emitter.ts`](https://github.com/microsoft/TypeScript/blob/main/src/compiler/emitter.ts), specifically within the `emitEnumDeclaration` function. For standard enums, this emitter generates a JavaScript object that maps enum names to their values. Numeric enums receive special treatment: the compiler creates bidirectional mappings where you can look up the name from the value (reverse mapping) in addition to the standard name-to-value lookup.

## Standard enum in TypeScript: Numeric and String Variants

TypeScript supports two primary flavors of standard enums that differ in their runtime behavior and mapping capabilities.

### Numeric Enums with Reverse Mapping

Numeric enums automatically generate reverse mappings, allowing you to access the enum member name from its numeric value:

```typescript
enum Direction {
  Up = 1,
  Down,
  Left,
  Right,
}

```

The compiler emits an object where `Direction.Up` equals `1` and `Direction[1]` equals `"Up"`. This bidirectional mapping is implemented in the emitter logic and consumes additional memory at runtime to support reverse lookups.

### String Enums Without Reverse Mapping

String enums provide named constants with string values but do not create reverse mappings:

```typescript
enum Status {
  Loading = "LOADING",
  Error = "ERROR",
  Success = "SUCCESS",
}

```

In [`src/compiler/utilities.ts`](https://github.com/microsoft/TypeScript/blob/main/src/compiler/utilities.ts), the `isEnumConst` helper function determines enum characteristics, while string enums emit only forward mappings (`Status.Loading` → `"LOADING"`), resulting in smaller runtime footprints than their numeric counterparts.

## const enum in TypeScript: Compile-Time Only Constants

Adding the `const` modifier to an enum declaration triggers aggressive compile-time optimizations that eliminate runtime objects entirely.

When processing a `const enum`, the compiler inlines the enum values directly into the usage sites. In [`src/compiler/transformers/ts.ts`](https://github.com/microsoft/TypeScript/blob/main/src/compiler/transformers/ts.ts), the transformation logic replaces enum member references with their literal values based on the `PreserveConstEnums` compiler flag. If this flag is disabled, no runtime code is emitted:

```typescript
const enum Permission {
  Read = 1 << 0,
  Write = 1 << 1,
  Execute = 1 << 2,
}

// Compiles to: const access = 1 | 2;
const access = Permission.Read | Permission.Write;

```

This inlining provides zero-runtime-cost constants but prevents iterating over enum members or using them as object keys at runtime.

## Enum-Like Alternatives Without Runtime Overhead

For scenarios requiring only type safety without emitted JavaScript, TypeScript offers several enum-like patterns that leverage the type system without relying on [`src/compiler/factory/nodeFactory.ts`](https://github.com/microsoft/TypeScript/blob/main/src/compiler/factory/nodeFactory.ts) to generate `EnumDeclaration` nodes.

### Union Types for Pure Type Safety

A union of string literal types provides exhaustive checking without any runtime representation:

```typescript
type Size = "small" | "medium" | "large";

function configure(s: Size) {
  // Type-safe compile-time checking with zero bytes emitted
}

```

This pattern avoids the runtime object creation entirely, unlike standard enums processed by the `createEnumDeclaration` factory function.

### as const Assertions for Frozen Objects

The `as const` assertion creates immutable objects that can be used for iteration while extracting types:

```typescript
const Role = {
  Admin: "ADMIN",
  User: "USER",
} as const;

type Role = keyof typeof Role; // "Admin" | "User"

```

This approach emits a frozen JavaScript object (unlike `const enum`, which emits nothing) while providing the same type-level exhaustiveness checking found in [`src/services/utilities.ts`](https://github.com/microsoft/TypeScript/blob/main/src/services/utilities.ts) through `SymbolFlags.Enum` handling.

### Ambient declare const enum

For type-only declarations that reference existing JavaScript constants, ambient declarations provide enum-like typing without emission:

```typescript
declare const enum Mode {
  Read,
  Write,
}

```

This declares the type information used by the type checker in [`src/compiler/utilities.ts`](https://github.com/microsoft/TypeScript/blob/main/src/compiler/utilities.ts) without invoking the `emitEnumDeclaration` logic, resulting in absolutely no output JavaScript.

## Choosing the Right enum Pattern in TypeScript

Selecting the appropriate enum construct depends on specific runtime requirements and performance constraints:

- **Standard numeric `enum`** – Use when you need bidirectional mapping (value → name) and runtime iteration capabilities. Best for configuration flags and status codes where reverse lookups are required.
- **Standard string `enum`** – Use when you need forward mapping only with readable string values at runtime. Ideal for action types in Redux or event names.
- **`const enum`** – Use when you need numeric constants with zero runtime overhead and no object allocation. Perfect for bitflags and performance-critical calculations.
- **Union types** – Use when you need type safety without any JavaScript emission. Best for library APIs where bundle size is critical.
- **`as const` objects** – Use when you need both type safety and runtime iteration over keys/values without enum-specific quirks.

## Summary

- **Standard enum declarations** processed by `parseEnumDeclaration` in [`src/compiler/parser.ts`](https://github.com/microsoft/TypeScript/blob/main/src/compiler/parser.ts) create runtime objects with member mappings.
- **Numeric enums** generate bidirectional mappings (name ↔ value), while **string enums** create only unidirectional mappings (name → value).
- **`const enum`** declarations are inlined at compile time by transformers in [`src/compiler/transformers/ts.ts`](https://github.com/microsoft/TypeScript/blob/main/src/compiler/transformers/ts.ts), producing zero runtime overhead when `PreserveConstEnums` is disabled.
- **Enum-like alternatives** such as union types and `as const` assertions provide type safety without invoking the emitter logic in [`src/compiler/emitter.ts`](https://github.com/microsoft/TypeScript/blob/main/src/compiler/emitter.ts).
- The choice between enum types depends on whether you need **reverse mapping**, **runtime iteration**, or **zero bundle size impact**.

## Frequently Asked Questions

### What is the difference between enum and const enum in TypeScript?

Standard `enum` declarations emit a JavaScript object that maps member names to values (and values back to names for numeric enums), consuming runtime memory and enabling reverse lookups. In contrast, `const enum` values are inlined directly into the compiled output by the transformer logic in [`src/compiler/transformers/ts.ts`](https://github.com/microsoft/TypeScript/blob/main/src/compiler/transformers/ts.ts), resulting in literal values with no runtime object creation. This means `const enum` members cannot be iterated or accessed dynamically using bracket notation.

### Why does my numeric enum have reverse mappings?

Numeric enums implement bidirectional mappings as a language feature to support common use cases like converting numeric error codes to human-readable names. During emission in [`src/compiler/emitter.ts`](https://github.com/microsoft/TypeScript/blob/main/src/compiler/emitter.ts), the `emitEnumDeclaration` function generates both the forward mapping (`Enum.Member = value`) and the reverse mapping (`Enum[value] = "Member"`). String enums do not receive this treatment because string values are not suitable for reverse object keys in the generated JavaScript.

### When should I use union types instead of enum in TypeScript?

Use union types when you require compile-time type safety without any runtime JavaScript emission, particularly in library code where minimizing bundle size is critical. Unlike enums processed through [`src/compiler/factory/nodeFactory.ts`](https://github.com/microsoft/TypeScript/blob/main/src/compiler/factory/nodeFactory.ts), union types exist only in the type system and are erased during compilation. They also prevent issues with enum merging (declaration merging) and provide stricter checking against accidental cross-enum compatibility that can occur with standard numeric enums.

### How does TypeScript handle enum declarations internally?

The TypeScript compiler processes enum declarations through a multi-stage pipeline: [`src/compiler/parser.ts`](https://github.com/microsoft/TypeScript/blob/main/src/compiler/parser.ts) creates `EnumDeclaration` syntax nodes via `parseEnumDeclaration`, the type checker in [`src/services/utilities.ts`](https://github.com/microsoft/TypeScript/blob/main/src/services/utilities.ts) validates members using `SymbolFlags.Enum`, and [`src/compiler/emitter.ts`](https://github.com/microsoft/TypeScript/blob/main/src/compiler/emitter.ts) generates the final JavaScript output through `emitEnumDeclaration`. For `const enum` members, the compiler also utilizes `isEnumConst` from [`src/compiler/utilities.ts`](https://github.com/microsoft/TypeScript/blob/main/src/compiler/utilities.ts) to determine whether to emit an object or inline the literal values during the transformation phase.