Blog ENI : Toute la veille numérique !
🎁 Jusqu'au 25/12 : 1 commande de contenus en ligne
= 1 chance de gagner un cadeau*. Cliquez ici
🎁 Jusqu'au 31/12, recevez notre
offre d'abonnement à la Bibliothèque Numérique. Cliquez ici

Les décorateurs

Introduction

Un décorateur permet d’ajouter un comportement à un élément lors de l’exécution du code. Les décorateurs prennent la forme de fonctions qui peuvent être par la suite exécutées en utilisant une expression. Celle-ci commence avec le caractère @, suivi du nom du décorateur à exécuter.

Syntaxe :

@DecoratorName 

Il n’existe pas de convention de nommage actée pour les décorateurs. Toutefois, la convention de nommage la plus communément utilisée est celle dite "PascalCase". Dans ce chapitre, c’est la convention qui sera utilisée dans les exemples.

Les décorateurs sont souvent utilisés pour appliquer des aspects techniques sur les objets, comme :

  • logger l’exécution d’une méthode,

  • injecter des dépendances,

  • notifier le changement de la valeur d’une propriété.

L’autre intérêt des décorateurs est qu’ils permettent d’ajouter des métadonnées. Celles-ci précisent des informations supplémentaires sur un élément. Elles offrent aussi la possibilité aux développeurs d’écrire du code de manière plus déclarative. Cette utilisation des décorateurs est très courante et il existe de nombreux Frameworks et bibliothèques...

Décorateurs expérimentaux

Pour utiliser les décorateurs expérimentaux, il est nécessaire d’activer les options de compilation dédiées lors de l’initialisation du fichier tsconfig.json. Lors de l’utilisation de la commande tsc --init, il faut ajouter les arguments --experimentalDecorators (qui permet d’activer l’utilisation des décorateurs dans TypeScript) et --emitDecoratorMetadata (qui permet d’injecter dans le code, lors de la compilation, les métadonnées autour des types. cf. section Métadonnées) pour activer le support complet des décorateurs dans TypeScript. 

Exemple :

tsc --init --experimentalDecorators --emitDecoratorMetadata 

Les deux options de compilation portent le même nom que les arguments dans le fichier tsconfig.json.

Exemple :

"experimentalDecorators": true, 
"emitDecoratorMetadata": true 

Par défaut, lors de l’initialisation, ces deux options sont disponibles dans le fichier tsconfig.json, mais commentées.

1. Décorateurs expérimentaux de classe

Une fonction peut être utilisée en tant que décorateur de classe à partir du moment où son type correspond à celui de ClassDecorator. Ce type est défini dans le fichier de déclaration de base de TypeScript (lib.d.ts) :

declare type ClassDecorator = <TFunction extends Function>( 
  target: TFunction 
) => TFunction | void; 

Le mot-clé type est utilisé en TypeScript pour définir des alias de type. Il sera abordé en détail dans la suite de cet ouvrage (cf. chapitre Système de types avancés). Le mot-clé declare est quant à lui utilisé dans les fichiers de définitions pour définir et typer un élément afin qu’il puisse être utilisé dans du code TypeScript.

Ce type définit que la fonction décoratrice accepte un paramètre dont le type est contraint, via l’utilisation d’un générique, à étendre celui de Function. Le paramètre target permet de récupérer le constructeur de la classe.

Exemple :

const LogClassName: ClassDecorator = target => { 
  console.log(target.name); 
}; 
 
// Log:...

Décorateurs ECMAScript

Pour utiliser les décorateurs ECMAScript, il n’est pas nécessaire d’activer d’options de compilation lors de l’initialisation du fichier tsconfig.json. Cette version des décorateurs étant native, elle est de base prise en charge par TypeScript à partir de la version 5.0.

Il est important de garder en tête que cette version des décorateurs est une première étape dans l’implémentation de la fonctionnalité et qu’elle n’est pas équivalente à celle des décorateurs expérimentaux.

Entre 2016 et 2022, les différents membres du groupe travaillant sur la standardisation des décorateurs dans ECMAScript ont eu beaucoup de difficultés pour se mettre d’accord. Cela vient principalement du fait que les décorateurs ont été introduits dans TypeScript très tôt et qu’ils ont ensuite permis le développement de bibliothèques et Frameworks utilisées par la suite dans de nombreux projets (comme Angular et NestJS par exemple). Il a été difficile de produire un standard autour des décorateurs permettant de répondre correctement à la problématique, tout en redéfinissant la base imposée par TypeScript, et en prenant en considération les applications existantes. Un consensus a été trouvé, mais certains points sont à noter :

  • Les décorateurs de paramètre ne font pas partie de la première implémentation des décorateurs ECMAScript. Ils viendront avec la version 2.0 de la spécification. 

  • Actuellement, aucun équivalent concernant les Métadonnées n’a été finalisé dans la spécification ECMAScript. Cette partie est à l’étude dans une autre proposition de standardisation.

En prenant en considération ces deux points, il n’est donc pas possible (à l’heure où cet ouvrage est écrit) de profiter pleinement des capacités introduites par les décorateurs expérimentaux via les décorateurs natifs. Toutefois, les capacités de ces derniers sont mieux définies et permettent de couvrir une grande partie des scénarios dans lesquelles...