web-dev-qa-db-fra.com

Énums en Javascript avec ES6

Je reconstruis un ancien projet Java en Javascript et me suis rendu compte qu'il n'y avait pas de bonne façon de faire des énumérations dans JS.

Le mieux que je puisse trouver est:

const Colors = {
    RED: Symbol("red"),
    BLUE: Symbol("blue"),
    GREEN: Symbol("green")
};
Object.freeze(Colors);

La const empêche la réattribution de Colors et le gel empêche la mutation des clés et des valeurs. J'utilise des symboles pour que Colors.RED ne soit pas égal à 0 ou à quoi que ce soit d'autre que lui-même.

Y at-il un problème avec cette formulation? Y a-t-il un meilleur moyen?


(Je sais que cette question est un peu répétitive, mais tous les Q/As précédents sont assez anciens et ES6 nous offre de nouvelles fonctionnalités.)


EDIT:

Une autre solution, qui traite le problème de la sérialisation, mais je pense qu’il reste des problèmes de domaine:

const enumValue = (name) => Object.freeze({toString: () => name});

const Colors = Object.freeze({
    RED: enumValue("Colors.RED"),
    BLUE: enumValue("Colors.BLUE"),
    GREEN: enumValue("Colors.GREEN")
});

En utilisant les références d'objet comme valeurs, vous obtenez le même évitement de collision que les symboles.

97
Eric the Red

Y a-t-il un problème avec cette formulation?

Je n'en vois pas.

Y a-t-il un meilleur moyen?

Je réduirais les deux déclarations en une seule:

const Colors = Object.freeze({
    RED:   Symbol("red"),
    BLUE:  Symbol("blue"),
    GREEN: Symbol("green")
});

Si vous n'aimez pas le passe-partout, comme les appels répétés Symbol, vous pouvez bien sûr aussi écrire une fonction d'assistance makeEnum qui crée la même chose à partir d'une liste de noms.

100
Bergi

Bien que vous utilisiez Symbol comme valeur d'enum pour les cas d'utilisation simples, il peut s'avérer utile de donner des propriétés aux énumérations. Cela peut être fait en utilisant un Object en tant que valeur enum contenant les propriétés.

Par exemple, nous pouvons donner à chacune des Colors un nom et une valeur hexadécimale:

/**
 * 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" }
});

L'inclusion de propriétés dans l'énumération évite d'avoir à écrire des instructions switch (et éventuellement d'oublier de nouveaux cas dans les instructions switch lorsqu'une énumération est étendue). L'exemple montre également les propriétés et types d'énumération documentés avec l'annotation annotation d'énumération JSDoc .

L'égalité fonctionne comme prévu avec Colors.RED === Colors.RED étant true et Colors.RED === Colors.BLUE étant false.

9
Justin Emery

Comme mentionné ci-dessus, vous pouvez également écrire une fonction d'assistance makeEnum():

function makeEnum(arr){
    let obj = {};
    for (let val of arr){
        obj[val] = Symbol(val);
    }
    return Object.freeze(obj);
}

Utilisez-le comme ceci:

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");
}
6
tonethar

Vérifiez comment TypeScript le fait-il . Fondamentalement, ils font ce qui suit:

const MAP = {};

MAP[MAP[1] = 'A'] = 1;
MAP[MAP[2] = 'B'] = 2;

MAP['A'] // 1
MAP[1] // A

Utilisez des symboles, geler un objet, tout ce que vous voulez.

5
givehug

Ceci est mon approche personnelle.

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);

Vous pouvez vérifier Enumify , une très bonne bibliothèque pour les énumérations ES6.

4
Emmanuel.B

Si vous n'avez pas besoin de pure ES6 et que vous pouvez utiliser TypeScript, il possède un Nice enum:

https://www.typescriptlang.org/docs/handbook/enums.html

2
Chris Halcrow

Peut-être que cette solution? :)

function createEnum (array) {
  return Object.freeze(array
    .reduce((obj, item) => {
      if (typeof item === 'string') {
        obj[item] = Symbol(item)
      }
      return obj
    }, {}))
}
1
Mateusz Stefański