-
Notifications
You must be signed in to change notification settings - Fork 13.2k
Description
🔍 Search Terms
The Problem: Traditional enum in TypeScript generates an IIFE (Immediately Invoked Function Expression) at runtime, which breaks "type-stripping".
The Proposal: Introduce a new syntax, such as const enum type Name { ... }, that behaves exactly like an as const object but provides the dedicated ergonomics of an enum. It should be 100% erasable, leaving only a simple object literal in the emitted JavaScript.
✅ Viability Checklist
- This wouldn't be a breaking change in existing TypeScript/JavaScript code
- This wouldn't change the runtime behavior of existing JavaScript code
- This could be implemented without emitting different JS based on the types of the expressions
- This isn't a runtime feature (e.g. library functionality, non-ECMAScript syntax with JavaScript output, new syntax sugar for JS, etc.)
- This isn't a request to add a new utility type: https://github.com/microsoft/TypeScript/wiki/No-New-Utility-Types
- This feature would agree with the rest of our Design Goals: https://github.com/Microsoft/TypeScript/wiki/TypeScript-Design-Goals
⭐ Suggestion
I propose a new, fully erasable version of enum that aligns with modern Type Stripping standards. This would provide the developer experience of an Enum (autocompletion, grouping, and type safety) but compile to a simple, standard JavaScript object literal—or be erased entirely if used only for types.
📃 Motivating Example
The Problem: "The Enum Tax"
Today, if you want a set of named constants in TypeScript, you have to choose between clean syntax (Enums) or clean output (Objects).
Standard Enums generate a "magic" IIFE (Immediately Invoked Function Expression) that is difficult for modern bundlers to tree-shake and impossible for "Type-Stripping" runtimes (like Node.js 23+) to handle without a heavy transpilation step.
typescript
// ❌ Current Enum: Generates 7+ lines of complex JS
enum Status {
Pending,
Active
}
// Resulting JS (Hard to optimize):
var Status;
(function (Status) {
Status[Status["Pending"] = 0] = "Pending";
Status[Status["Active"] = 1] = "Active";
})(Status || (Status = {}));
💻 Use Cases
- What do you want to use this for? for my personal projects
- What shortcomings exist with current approaches?
- What workarounds are you using in the meantime?