
Le match #1 : Enums vs Unions Types en Typescript
Jour de match !
Plutôt Enums ou Unions Type en Typescript ? Quel est le plus performant ? Quel est le plus pratique ? Des tips d’utilisation ?
Le match s’annonce des plus intenses. On va donc découvrir comment utiliser les Enums et les Unions Type et quels sont leurs défauts et leurs qualités.
Enums
La documentation officielle de Typescript nous dit que : un Enum permet aux développeurs de définir un ensemble de constantes nommées et de simplifier la documentation de notre projet.
enum FamilyMembersEnum {
MOTHER, //0
FATHER, //1
SISTER, //2
BROTHER //3
}
Grâce au code ci-dessus, on a défini 4 constantes qui prennent chacune une valeur (de 0 à 4 par défaut) et qui sont regroupées en un groupe de données.
Par défaut, les valeurs associées aux mot-clés seront des number en commençant par 0 dans l’ordre croissant. Il est possible de définir ces valeurs avec des string comme ci-dessous :
enum FamilyMembersEnum {
MOTHER = 'mother',
FATHER = 'father'
...
}
Union type
Si on se réfère à la documentation officielle Typescript, les Literals Type sont des types qui font référence à une string. En utilisant les _unions_, on peut donc faire référence à plusieurs string.
type FamilyMembersType = 'mother' | 'father' | 'sister' | 'brother'
Avec cette ligne de code, on indique à Typescript que le type _FamilyMembers_ peut prendre uniquement les valeurs indiquées soient : mother, father, sister, brother
Accéder aux valeurs / Accessing
C’est ici que le match commence !
Comment accéder aux valeurs de chacune des solutions ?
Enums
Pour les Enums, il faut faire référence au nom de celui-ci suivi du nom de la constante.
let varEnum: FamilyMembersEnum = FamilyMembersEnum.MOTHER
Dans le cas d’une fonction qui prend en paramètre un Enum, on doit importer l’Enum dans le fichier courant (à gauche).
Union Type
Pour les Unions Type, il faut simplement réécrire la valeur.
let varType: FamilyMembersType = 'mother'
Dans le cas d’une fonction utilisant en argument un Union Type, on aura accès à l’auto-complétion sans devoir importer le type.
1️⃣ points pour les Unions Type
Etendre / Extending
Union Type
Lorsque l’on se sert des Unions Type, on peut utiliser toute la puissance des types et créer des unions d’unions (Unionception 😉 ).
type RedFruits = 'strawberry' | 'cherry'
type YellowFruits = 'banana' | 'lemon'
type Fruits = RedFruits | YellowFruits //'strawberry' | 'cherry' | 'banana' | 'lemon'
Enums
Ceci n’est tout simplement pas réalisable avec des Enumérateurs.
2️⃣ points pour les Unions Type
—
Itération / Iterating
Il peut être intéressant dans certains cas d’itérer sur les valeurs définies.
Enums
Avec les Enums, rien de plus simple !
for (const member of FamilyMembersEnum) {
}
/!\ Il n’est pas possible d’itérer sur un Enum déclaré en const
Union Type
Pour les Unions Type, ce n’est pas possible. En effet, lorsque le code typescript est transpilé en Javascript, les types ne sont pas conservés et n’existent plus. Javascript est donc incapable d’identifier les valeurs de l’Union Type.
1️⃣ points pour les Enums
—
Renommage / Renaming
Union Type
Pour changer la valeur d’un Union Type, pas d’autre choix que de modifier tous les fichiers où vous l’utilisez. Pour les plus malins ;), notre ami VSCode est capable de grandes choses.
Enums
Pour les Enums, on change la valeur au niveau de la déclaration de celui-ci et … c’est tout !
2️⃣ points pour les Enums
Performances
Union Type
Les types ne sont utilisés que pour la phase de développement et sont donc supprimés lors de la transpilation.
type FamilyMembersType = 'mother' | 'father' | 'sister' | 'brother'
Notre type FamilyMembersType disparaît lors de la transpilation
Pour transpiler un fichier Typescript : tsc nom_du_fichier.ts
Enums
Pour notre enum FamilyMembresEnum, la transpilation donne quelque chose de plus complexe.
// Fichier source
enum FamilyMembersEnum {
MOTHER = 'mother',
FATHER = 'father',
SISTER = 'sister',
BROTHER = 'brother'
}
// Après transpilation
var FamilyMembersEnum;
(function (FamilyMembersEnum) {
FamilyMembersEnum[FamilyMembersEnum["MOTHER"] = 0] = "MOTHER";
FamilyMembersEnum[FamilyMembersEnum["FATHER"] = 1] = "FATHER";
FamilyMembersEnum[FamilyMembersEnum["SISTER"] = 2] = "SISTER";
FamilyMembersEnum[FamilyMembersEnum["BROTHER"] = 3] = "BROTHER";
})(FamilyMembersEnum = exports.FamilyMembersEnum || (exports.FamilyMembers
Si on déclare un Enum avec le mot clé const, l’Enum adoptera le même comportement que les types lors de la transpilation et sera donc voué à disparaître. Les références aux Enums sont directement remplacés par la valeur.
// Fichier source
const enum FamilyMembersEnum {
MOTHER = 'mother',
FATHER = 'father',
SISTER = 'sister',
BROTHER = 'brother'
}
const member = FamilyMembersEnum.SISTER
//Après transpilation
var member = 'sister' /* SISTER */
A condition d’utiliser le mot clé const sur les Enums, égalité parfaite !
Pour finir
Enums
Les Numerics Enums ne sont pas protégés
Si on déclare une fonction avec comme paramètre un Numeric Enum.
enum FamilyMembersEnum {
MOTHER, //0
FATHER, //1
SISTER, //2
BROTHER //3
}
function getFamilyMembers(member: FamilyMembersEnum): void;
getFamilyMembers(30); // <--- ne génère pas d'erreur Typescript
Union Type
Les Unions Type ne sont pas lisibles
En choisissant d’utiliser les unions type, on accepte d’ajouter des valeurs dite « brutes » directement dans le code ce qui complexifie la relecture de code et le refactor.
Conclusion
Nous avons pu observer un match très serré entre les deux joueurs. Même si les Unions Type étaient très bien parti avec une entame de match quasiment parfaite, les Enums ont su se démarquer par leurs qualités. C’est finalement un très beau match nul que nous ont fait vivre ces 2 équipes !
Voici le résumé du match
Enums | Union Type | |
Accéder aux valeurs | 0️⃣ | 1️⃣ |
Etendre | 0️⃣ | 2️⃣ |
Itération | 1️⃣ | 0️⃣ |
Renommage | 2️⃣ | 0️⃣ |
Performances | 2️⃣ | 2️⃣ |
Vous l’aurez compris, chacune des méthodes a des avantages et des inconvénients.
Mon avis
Je n’ai pas choisi de bannir l’un ou l’autre et j’utilise les 2 solutions dans mes projets. J’utilise les Enums (uniquement en const
) dans la plupart des situations, car je trouve qu’ils apportent une meilleure lecture du code par leur nom qui définit un groupe et une valeur : GROUPE.VALEUR
J’utilise les Unions Type dans les cas qui nécessitent de faire des unions d’union.
Et vous, quelles sont vos utilisations des Unions Type et des Enums ?