Fundamentals 10 min read

Why TypeScript Seems to Discourage Enums and What Alternatives Exist

This article explains the new --erasableSyntaxOnly option in TypeScript, distinguishes erasable from non‑erasable syntax, shows why enums are considered problematic, and presents several practical alternatives such as const enums, template literal types, union types, const assertions, and class‑based enums.

Rare Earth Juejin Tech Community
Rare Earth Juejin Tech Community
Rare Earth Juejin Tech Community
Why TypeScript Seems to Discourage Enums and What Alternatives Exist

When TypeScript 5.8 introduced the --erasableSyntaxOnly compiler flag, it restricted code to use only erasable syntax—constructs that disappear after compilation and generate no runtime JavaScript, such as type , interface , and simple variable declarations.

Enums are classified as non‑erasable syntax because they produce additional JavaScript code (a bidirectional mapping) and therefore trigger a compilation error when --erasableSyntaxOnly is enabled:

enum METHOD { ADD = 'add' }
// Using enum with erasableSyntaxOnly => error

The flag was added to align TypeScript with recent Node.js changes that allow direct execution of TypeScript files containing only erasable syntax, while still requiring explicit handling for non‑erasable constructs.

Enums have three major drawbacks:

Default numeric values start at 0 , which can unintentionally accept raw numbers and weaken type safety.

Enum values cannot be used as literal types, preventing direct usage of the literal string values.

They generate extra runtime code, increasing bundle size and execution overhead.

Several alternatives can replace enums depending on the use case:

1. const enum

Compiles away to inline constants, eliminating runtime code, but it has compatibility issues with declaration files and isolated modules.

const enum METHOD { ADD = 'add', DELETE = 'delete' }
function doAction(method: METHOD) { /* ... */ }

2. Template Literal Types

Wrap an enum in a template literal type to accept both the enum and its literal values, though runtime overhead remains.

enum METHOD { ADD = 'add', DELETE = 'delete' }
type METHOD_STRING = `${METHOD}`;
function doAction(method: METHOD_STRING) { /* ... */ }

3. Union Types

Define a union of allowed string literals; this provides strict value checking but requires manual updates when the set changes.

type METHOD = 'add' | 'delete' | 'update' | 'query';
function doAction(method: METHOD) { /* ... */ }

4. as const Object Literals

Declare a constant object and infer a literal type from its values, offering both type safety and easy maintenance.

const METHOD = { ADD: 'add', DELETE: 'delete' } as const;
type METHOD_TYPE = typeof METHOD[keyof typeof METHOD];
function doAction(method: METHOD_TYPE) { /* ... */ }

5. Class‑Based Enum Pattern

Implement an enum‑like class with static instances, providing full OOP flexibility and runtime behavior.

export default class EnumBase { /* implementation omitted for brevity */ }
export class ENApproveState extends EnumBase {
  static readonly NOTAPPROVED = new ENApproveState('1', '未审核');
  static readonly APPROVED = new ENApproveState('2', '已审核');
  // ... other states
}

In summary, TypeScript’s --erasableSyntaxOnly option reflects a focus on reducing runtime overhead rather than a direct deprecation of enums. Developers can choose the most suitable replacement based on their needs, with as const object literals being a commonly recommended approach.

frontendTypeScriptenumType SafetyalternativeserasableSyntaxOnly
Rare Earth Juejin Tech Community
Written by

Rare Earth Juejin Tech Community

Juejin, a tech community that helps developers grow.

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.