I'm rebuilding an old Java project in Javascript, and realized that there's no good way to do enums in JS.
The best I can come up with is:
const Colors = {
RED: Symbol("red"),
BLUE: Symbol("blue"),
GREEN: Symbol("green")
};
Object.freeze(Colors);
The const
keeps Colors
from being reassigned, and freezing it prevents mutating the keys and values. I'm using Symbols so that Colors.RED
is not equal to 0
, or anything else besides itself.
Is there a problem with this formulation? Is there a better way?
(I know this question is a bit of a repeat, but all the previous Q/As are quite old, and ES6 gives us some new capabilities.)
EDIT:
Another solution, which deals with the serialization problem, but I believe still has realm issues:
const enumValue = (name) => Object.freeze({toString: () => name});
const Colors = Object.freeze({
RED: enumValue("Colors.RED"),
BLUE: enumValue("Colors.BLUE"),
GREEN: enumValue("Colors.GREEN")
});
By using object references as the values, you get the same collision-avoidance as Symbols.
Introduction to ES6 Enum. ES6 provides different types of features to the user, in which that enum is one of the features that are provided by the ES6. Basically, enum allows the developer to define the set of name constants that the developer wants as per their requirement.
Enums are not supported in JavaScript natively. We can however create Enums using Object. freeze by creating objects containing all the enumerable properties and then freezing the object so that no new enum can be added to it.
Enums are types that contain a limited number of fixed values, as opposed to types like Number or String which can have a wide range of values.
Enums are one of the few features TypeScript has which is not a type-level extension of JavaScript. Enums allow a developer to define a set of named constants. Using enums can make it easier to document intent, or create a set of distinct cases. TypeScript provides both numeric and string-based enums.
Is there a problem with this formulation?
I don't see any.
Is there a better way?
I'd collapse the two statements into one:
const Colors = Object.freeze({
RED: Symbol("red"),
BLUE: Symbol("blue"),
GREEN: Symbol("green")
});
If you don't like the boilerplate, like the repeated Symbol
calls, you can of course also write a helper function makeEnum
that creates the same thing from a list of names.
Whilst using Symbol
as the enum value works fine for simple use cases, it can be handy to give properties to enums. This can be done by using an Object
as the enum value containing the properties.
For example we can give each of the Colors
a name and hex value:
/**
* Enum for common colors.
* @readonly
* @enum {{name: string, hex: string}}
*/
const Colors = Object.freeze({
RED: { name: "red", hex: "#f00" },
BLUE: { name: "blue", hex: "#00f" },
GREEN: { name: "green", hex: "#0f0" }
});
Including properties in the enum avoids having to write switch
statements (and possibly forgetting new cases to the switch statements when an enum is extended). The example also shows the enum properties and types documented with the JSDoc enum annotation.
Equality works as expected with Colors.RED === Colors.RED
being true
, and Colors.RED === Colors.BLUE
being false
.
This is my personal approach.
class ColorType {
static get RED () {
return "red";
}
static get GREEN () {
return "green";
}
static get BLUE () {
return "blue";
}
}
// Use case.
const color = Color.create(ColorType.RED);
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With