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 C
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.
Here is my approach, including some helper methods
export default class Enum {
constructor(name){
this.name = name;
}
static get values(){
return Object.values(this);
}
static forName(name){
for(var enumValue of this.values){
if(enumValue.name === name){
return enumValue;
}
}
throw new Error('Unknown value "' + name + '"');
}
toString(){
return this.name;
}
}
-
import Enum from './enum.js';
export default class ColumnType extends Enum {
constructor(name, clazz){
super(name);
this.associatedClass = clazz;
}
}
ColumnType.Integer = new ColumnType('Integer', Number);
ColumnType.Double = new ColumnType('Double', Number);
ColumnType.String = new ColumnType('String', String);
you can also use es6-enum package (https://www.npmjs.com/package/es6-enum). It's very easy to use. See the example below:
import Enum from "es6-enum";
const Colors = Enum("red", "blue", "green");
Colors.red; // Symbol(red)
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
.
Here is an Enum
factory that avoids realm issues by using a namespace and Symbol.for
:
const Enum = (n, ...v) => Object.freeze(v.reduce((o, v) => (o[v] = Symbol.for(`${n}.${v}`), o), {}));
const COLOR = Enum("ACME.Color", "Blue", "Red");
console.log(COLOR.Red.toString());
console.log(COLOR.Red === Symbol.for("ACME.Color.Red"));
You could use ES6 Map
const colors = new Map([
['RED', 'red'],
['BLUE', 'blue'],
['GREEN', 'green']
]);
console.log(colors.get('RED'));