A More Idiomatic Enum for JavaScript
- Idiomatic to JavaScript
- Semantic
- Progressive
- Arbitrary value types
- Mergeable
- Straightforward desugaring
- Straightforward TypeScript typing
Basic Syntax
enum STATUS {
Ready: 0,
Pending: 1,
Done: 2
};
Desugaring: Object + (1. Pure syntactic sugar OR 2. Frozen object)
// Option 1: Pure syntactic sugar (for readability)
const STATUS = {
Ready: 0,
Pending: 1,
Done: 2,
};
// Option 2: Frozen object (with runtime immutability)
const STATUS = Object.freeze({
Ready: 0,
Pending: 1,
Done: 2,
});
Arbitrary Value Types
enum STATUS {
Ready: 0,
Pending: "pending",
Done: true,
Error: null,
Warn: {}
}
Merging: {...enum, ...object}
enum APP_STATUS {
Ready: "ready",
Pending: "pending",
Done: "done"
}
enum USER_STATUS {
LoggedIn: "logged-in",
LoggedOut: "logged-out"
}
const TEST_STATUS = {
Success: "success",
Error: "error"
};
enum STATUS {
...APP_STATUS,
...USER_STATUS,
...TEST_STATUS
}
Design Rationale: No Reverse Mapping
The decision to omit reverse mapping is a deliberate choice to keep the feature idiomatic to JavaScript.
- Idiomatic & Predictable: JS developers are accustomed to standard object semantics. Adding reverse mapping introduces hidden complexity that breaks the βwhat you see is what you getβ intuition.
- Rarely Used: In practice, the need for
STATUS[1]is extremely rare compared toSTATUS.Ready. - Ambiguity with Shared Values: Reverse mapping is fundamentally broken when different keys map to the same value. For example, if
Ready: 1andSuccess: 1both exist, a reverse mapping likeSTATUS[1]is ambiguous. Plain objects naturally handle this by just retaining the key-value structure.
For cases where reverse lookup is strictly necessary, developers can easily and explicitly use Object.entries() or Object.keys() to build a reverse map, paying only for what they actually use.