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.
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 => errorThe 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.
Rare Earth Juejin Tech Community
Juejin, a tech community that helps developers grow.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.