Skip to content

Le texte dactylographié a des unions, les énumérations sont-elles donc redondantes ?

Solution:

Autant que je sache, ils ne sont pas redondants, pour la très simple raison que les types d’union sont purement un concept de temps de compilation alors que les énumérations sont en fait transpilées et se retrouvent dans le javascript résultant (échantillon).

Cela vous permet de faire certaines choses avec les énumérations, qui sont autrement impossibles avec les types d’union (comme l’énumération des valeurs d’énumération possibles)

Avec les versions récentes de TypeScript, il est facile de déclarer des types d’union itérables. Par conséquent, vous devriez préférer les types union aux énumérations.

Comment déclarer des types d’union itérables

const permissions = ['read', 'write', 'execute'] as const;
type Permission = typeof permissions[number]; // 'read' | 'write' | 'execute'

// you can iterate over permissions
for (const permission of permissions) {
  // do something
}

Lorsque les valeurs réelles du type union ne se décrivent pas très bien, vous pouvez les nommer comme vous le faites avec les énumérations.

// when you use enum
enum Permission {
  Read = 'r',
  Write="w",
  Execute="x"
}

// union type equivalent
const Permission = {
  Read: 'r',
  Write: 'w',
  Execute: 'x'
} as const;
type Permission = typeof Permission[keyof typeof Permission]; // 'r' | 'w' | 'x'

// of course it's quite easy to iterate over
for (const permission of Object.values(Permission)) {
  // do something
}

Ne manquez pas as const affirmation qui joue le rôle crucial dans ces modèles.

Pourquoi n’est-il pas bon d’utiliser des énumérations ?

1. Les énumérations non constantes ne correspondent pas au concept “un sur-ensemble typé de JavaScript”

Je pense que ce concept est l’une des raisons cruciales pour lesquelles TypeScript est devenu si populaire parmi les autres langages altJS. Les énumérations non-const violent le concept en émettant des objets JavaScript qui vivent au runtime avec une syntaxe qui n’est pas compatible avec JavaScript.

2. Les énumérations Const ont quelques pièges

Les énumérations Const ne peuvent pas être transpilées avec Babel

Il existe actuellement deux solutions de contournement pour ce problème : se débarrasser des énumérations const manuellement ou avec le plugin babel-plugin-const-enum.

Déclarer des const enums dans un contexte ambiant peut être problématique

Les énumérations constantes ambiantes ne sont pas autorisées lorsque le --isolatedModules le drapeau est fourni. Un membre de l’équipe TypeScript dit que “const enum sur DT n’a vraiment pas de sens” (DT fait référence à DefinitelyTyped) et “Vous devriez utiliser un type d’union de littéraux (chaîne ou nombre) à la place” des énumérations const dans le contexte ambiant.

Const énumérations sous --isolatedModules flag se comporte étrangement même en dehors d’un contexte ambiant

J’ai été surpris de lire ce commentaire sur GitHub et j’ai confirmé que le comportement est toujours vrai avec TypeScript 3.8.2.

3. Les énumérations numériques ne sont pas sécurisées

Vous pouvez affecter n’importe quel numéro aux énumérations numériques.

enum ZeroOrOne {
  Zero = 0,
  One = 1
}
const zeroOrOne: ZeroOrOne = 2; // no error!!

4. La déclaration des énumérations de chaîne peut être redondante

On voit parfois ce genre d’énumérations de chaîne :

enum Day {
  Sunday = 'Sunday',
  Monday = 'Monday',
  Tuesday = 'Tuesday',
  Wednesday = 'Wednesday',
  Thursday = 'Thursday',
  Friday = 'Friday',
  Saturday = 'Saturday'
}

Je dois admettre qu’il existe une fonctionnalité d’énumération qui n’est pas réalisée par les types d’union

Même s’il est évident d’après le contexte que la valeur de chaîne est incluse dans l’énumération, vous ne pouvez pas l’affecter à l’énumération.

enum StringEnum {
  Foo = 'foo'
}
const foo1: StringEnum = StringEnum.Foo; // no error
const foo2: StringEnum = 'foo'; // error!!

Cela unifie le style d’affectation de valeur enum dans tout le code en éliminant l’utilisation de valeurs de chaîne ou de littéraux de chaîne. Ce comportement n’est pas cohérent avec la façon dont le système de type TypeScript se comporte dans les autres endroits et est assez surprenant et certaines personnes qui pensaient que cela devrait être corrigé ont soulevé des problèmes (ceci et cela), dans lesquels il est mentionné à plusieurs reprises que l’intention des énumérations de chaîne est pour fournir des types de chaînes “opaques”: c’est-à-dire qu’ils peuvent être changés sans modifier les consommateurs.

enum Weekend {
  Saturday = 'Saturday',
  Sunday = 'Sunday'
}
// As this style is forced, you can change the value of
// Weekend.Saturday to 'Sat' without modifying consumers
const weekend: Weekend = Weekend.Saturday;

Notez que cette “opacité” n’est pas parfaite car l’affectation de valeurs enum aux types littéraux de chaîne n’est pas limitée.

enum Weekend {
  Saturday = 'Saturday',
  Sunday = 'Sunday'
}
// The change of the value of Weekend.Saturday to 'Sat'
// results in a compilation error
const saturday: 'Saturday' = Weekend.Saturday;

Si vous pensez que cette fonctionnalité “opaque” est si précieuse que vous pouvez accepter tous les inconvénients que j’ai décrits ci-dessus en échange, vous ne pouvez pas abandonner les énumérations de chaîne.

Comment éliminer les énumérations de votre base de code

Avec le no-restricted-syntax règle d’ESLint, comme décrit.

Il y a quelques raisons pour lesquelles vous pourriez vouloir utiliser un enum

  • Vous pouvez itérer sur un enum.
  • Vous pouvez utiliser un enum comme flags. Indicateurs de bits
  • Voici quelques cas d’utilisation. Enums TypeScript Deep Dive.

Je vois que les grands avantages de l’utilisation d’une union sont qu’ils fournissent un moyen succinct de représenter une valeur avec plusieurs types et qu’ils sont très lisibles.
let x: number | string

EDIT : à partir de TypeScript 2.4, les énumérations prennent désormais en charge les chaînes.

enum Colors {
  Red = "RED",
  Green = "GREEN",
  Blue = "BLUE",
} 



Articles Similaires

Laisser un commentaire

Votre adresse e-mail ne sera pas publiée. Les champs obligatoires sont indiqués avec *