qué - Enums en Javascript con ES6
qué es numeric enums typescript (10)
Estoy reconstruyendo un antiguo proyecto Java en Javascript, y me di cuenta de que no hay una buena manera de hacer enumeraciones en JS.
Lo mejor que se me ocurre es:
const Colors = {
RED: Symbol("red"),
BLUE: Symbol("blue"),
GREEN: Symbol("green")
};
Object.freeze(Colors);
La
const
evita que los
Colors
se reasignen, y su congelación evita la mutación de las claves y los valores.
Estoy usando símbolos para que
Colors.RED
no sea igual a
0
, ni nada más aparte de sí mismo.
¿Hay algún problema con esta formulación? ¿Hay una mejor manera?
(Sé que esta pregunta se repite un poco, pero todas las preguntas y respuestas anteriores son bastante antiguas y ES6 nos brinda algunas capacidades nuevas).
EDITAR:
Otra solución, que trata el problema de la serialización, pero creo que todavía tiene problemas de dominio:
const enumValue = (name) => Object.freeze({toString: () => name});
const Colors = Object.freeze({
RED: enumValue("Colors.RED"),
BLUE: enumValue("Colors.BLUE"),
GREEN: enumValue("Colors.GREEN")
});
Al utilizar referencias de objetos como valores, obtiene la misma prevención de colisiones que los símbolos.
¿Hay algún problema con esta formulación?
No veo ninguno
¿Hay una mejor manera?
Colapsaría las dos declaraciones en una:
const Colors = Object.freeze({
RED: Symbol("red"),
BLUE: Symbol("blue"),
GREEN: Symbol("green")
});
Si no le gusta la repetitiva, como las llamadas repetidas de
Symbol
, por supuesto, también puede escribir una función auxiliar
makeEnum
que cree lo mismo a partir de una lista de nombres.
Como se mencionó anteriormente, también podría escribir una función auxiliar
makeEnum()
:
function makeEnum(arr){
let obj = {};
for (let val of arr){
obj[val] = Symbol(val);
}
return Object.freeze(obj);
}
Úselo así:
const Colors = makeEnum(["red","green","blue"]);
let startColor = Colors.red;
console.log(startColor); // Symbol(red)
if(startColor == Colors.red){
console.log("Do red things");
}else{
console.log("Do non-red things");
}
Comprueba cómo TypeScript lo hace . Básicamente hacen lo siguiente:
const MAP = {};
MAP[MAP[1] = ''A''] = 1;
MAP[MAP[2] = ''B''] = 2;
MAP[''A''] // 1
MAP[1] // A
Usa símbolos, congela objetos, lo que quieras.
Este es mi enfoque personal.
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);
Podrías usar ES6 Map
const colors = new Map([
[''RED'', ''red''],
[''BLUE'', ''blue''],
[''GREEN'', ''green'']
]);
console.log(colors.get(''RED''));
Puede consultar Enumify , una biblioteca muy buena y bien presentada para enumeraciones de ES6.
Si bien usar
Symbol
como el valor de enumeración funciona bien para casos de uso simples, puede ser útil otorgar propiedades a las enumeraciones.
Esto se puede hacer usando un
Object
como el valor de enumeración que contiene las propiedades.
Por ejemplo, podemos dar a cada uno de los
Colors
un nombre y un valor hexadecimal:
/**
* 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" }
});
La inclusión de propiedades en la enumeración evita tener que escribir sentencias de
switch
(y posiblemente olvidar nuevos casos en las sentencias de cambio cuando se extiende una enumeración).
El ejemplo también muestra las propiedades y tipos de enumeración documentados con la
anotación de enumeración JSDoc
.
La igualdad funciona como se esperaba con
Colors.RED === Colors.RED
es
true
y
Colors.RED === Colors.BLUE
es
false
.
Si no necesita
un
ES6
puro
y puede usar el Script mecanografiado, tiene una buena
enum
:
Tal vez esta solución? :)
function createEnum (array) {
return Object.freeze(array
.reduce((obj, item) => {
if (typeof item === ''string'') {
obj[item] = Symbol(item)
}
return obj
}, {}))
}
También puede usar el paquete es6-enum ( https://www.npmjs.com/package/es6-enum ). Es muy fácil de usar. Vea el ejemplo a continuación.