Programmation web

TypeScript 5.5 Decorators : explication + cas concrets

Apprenez à utiliser les décorateurs TypeScript 5.5. Configuration tsconfig, exemples de validation et mise en cache pour optimiser votre code moderne.

13 min de lecture 13 févr. 2026 2 578 mots

Avec une solide expérience en systèmes et langages typés, notre équipe a constaté à quel point la maîtrise des langages de programmation comme TypeScript est essentielle pour optimiser les workflows. TypeScript 5.5, lancé en 2024, a enrichi le langage avec des fonctionnalités avancées, y compris une prise en charge améliorée des décorateurs. Ces derniers permettent d'ajouter des métadonnées à une classe ou une méthode, facilitant ainsi la lecture et la maintenance du code, tout en améliorant la productivité des développeurs.

Les décorateurs en TypeScript offrent une façon élégante de manipuler les classes et leurs méthodes, permettant d'implémenter des fonctionnalités comme la journalisation, la vérification des autorisations ou encore la gestion des erreurs sans alourdir le code. Vous allez découvrir comment ces outils peuvent transformer votre façon de coder, en rendant le développement d'applications plus structuré et efficace. En maîtrisant les décorateurs, vous pourrez développer des applications robustes et évolutives, tout en respectant les principes SOLID.

Dans ce tutoriel, vous apprendrez à créer vos propres décorateurs et à les appliquer dans des cas concrets, comme la validation des entrées utilisateur et le suivi des performances. Vous découvrirez également comment intégrer ces techniques dans un projet TypeScript en utilisant des frameworks populaires tels que Angular ou NestJS. À la fin, vous serez capable de construire une application où les décorateurs simplifient le code, rendant le développement plus fluide et agréable.

Introduction aux décorateurs TypeScript

Comprendre les décorateurs

Les décorateurs en TypeScript sont des annotations qui ajoutent des métadonnées à des classes, méthodes ou propriétés. Cela permet d'étendre les fonctionnalités d'une classe sans modifier directement son code source. Par exemple, vous pouvez appliquer un décorateur pour logger les appels de méthode ou pour valider les entrées. Cela crée une séparation des préoccupations, rendant le code plus propre et plus facile à maintenir.

Un décorateur est une fonction qui reçoit en argument la cible à décorer. Vous pouvez interagir avec la classe ou la méthode afin de modifier son comportement. La syntaxe des décorateurs repose sur le préfixe @, ce qui facilite leur identification dans le code. En utilisant des décorateurs, vous pouvez atteindre une modularité accrue dans vos applications.

  • Modularité accrue
  • Séparation des préoccupations
  • Facilité de maintenance
  • Interception des comportements

Voici un exemple simple (TypeScript) qui journalise les appels d'une méthode :

function Log(target: any, key: string, descriptor: PropertyDescriptor) {
  const originalMethod = descriptor.value;

  descriptor.value = function(...args: any[]) {
    console.log(`Appel de ${key} avec arguments : ${JSON.stringify(args)}`);
    return originalMethod.apply(this, args);
  };

  return descriptor;
}

Ce code permet de logger chaque appel de la méthode décorée.

Type de décorateur Description Exemple d'utilisation
Classe Affecte une classe entière Décorateur pour un service
Méthode Affecte une méthode spécifique Décorateur de logging
Propriété Affecte une propriété de classe Décorateur de validation

Configuration (tsconfig.json) pour les décorateurs

Avant d'utiliser des décorateurs dans un projet TypeScript, il est important de configurer le compilateur. Selon la syntaxe (ancienne ou nouvelle / standardisée) vous devez activer les options appropriées dans tsconfig.json. Ci-dessous un rappel des options courantes :

  • Ancienne (legacy) : activez experimentalDecorators et, si vous avez besoin des métadonnées de type, emitDecoratorMetadata. L'option emitDecoratorMetadata génère des informations de type pour les décorateurs (nécessite souvent la librairie reflect-metadata au runtime).
  • Nouvelle / standardisée : TypeScript 5.5 et supprime progressivement la dépendance exclusive à experimentalDecorators en favorisant des options nommées comme decorators et decoratorMetadata. Activez la paire adaptée à votre cible (vérifiez la version du compilateur utilisée dans votre pipeline).

Exemple de tsconfig.json montrant les deux approches (JSONC - commentaires autorisés dans tsconfig.json) :

{
  "compilerOptions": {
    "target": "ES2022",
    "module": "commonjs",
    "strict": true,

    // Option legacy (TypeScript <-> décorateurs classiques)
    "experimentalDecorators": true,
    "emitDecoratorMetadata": true,

    // Option nouvelle/standard (TypeScript 5.5+)
    // Activez si votre chaîne d'outils supporte la nouvelle implémentation
    "decorators": true,
    "decoratorMetadata": true
  }
}

Si vous utilisez emitDecoratorMetadata, n'oubliez pas d'installer et d'importer reflect-metadata au démarrage de votre application pour rendre les métadonnées disponibles au runtime :

// src/main.ts
import "reflect-metadata"; // npm i reflect-metadata@^0.1.13

// ... bootstrap de l'application (ex: NestJS, Express...)

Dépannage rapide :

  • Après modification du tsconfig.json, redémarrez votre tsserver (éditeur) et le processus de build pour que les options soient prises en compte.
  • Si vous utilisez Babel, configurez @babel/plugin-proposal-decorators (mode compatible avec la syntaxe que vous ciblez) et @babel/plugin-proposal-class-properties selon les recommandations de Babel.
  • Vérifiez la version de TypeScript dans package.json (TypeScript 5.5+ recommandé pour la nouvelle API).

Diagramme : flux d'un décorateur

Le diagramme ci-dessous illustre le flux d'exécution lorsqu'un décorateur est appliqué à une classe et à une méthode : le décorateur s'attache à la cible au moment de l'évaluation (chargement du module) et peut modifier le prototype ou l'implémentation de la méthode avant les appels ultérieurs.

Flux d'application d'un décorateur Diagramme séquentiel montrant le chargement de la classe, l'évaluation du décorateur et l'enveloppement final de la méthode. 1. Classe chargée Analyse du code source 2. Décorateur évalué Exécution de la fonction 3. Méthode injectée ou enveloppée Comportement modifié
Processus d'application d'un décorateur : de la détection de la classe à la modification dynamique de la logique des méthodes.

Comprendre les différents types de décorateurs

Les catégories de décorateurs

Il existe trois types principaux de décorateurs en TypeScript : les décorateurs de classe, de méthode et de propriété. Les décorateurs de classe sont appliqués à la déclaration d'une classe, permettant de modifier le comportement d'ensemble de la classe (ajout de métadonnées, injection de dépendances, enregistrement dans un conteneur IoC).

Les décorateurs de méthode sont appliqués à des méthodes spécifiques. Ils interviennent lorsque la méthode est appelée, ce qui permet d'ajouter des fonctionnalités comme le logging, la validation des données ou la mise en cache. Les décorateurs de propriété vous permettent de contrôler l'accès aux propriétés d'une classe, en ajoutant des validations ou des transformations à l'assignation.

  • Décorateurs de classe
  • Décorateurs de méthode
  • Décorateurs de propriété
  • Décorateurs d'accessibilité (get/set) et paramètre

Exemple de décorateur de validation sur une méthode (TypeScript) :

function Validate(target: any, key: string, descriptor: PropertyDescriptor) {
  const originalMethod = descriptor.value;

  descriptor.value = function(...args: any[]) {
    if (!isValid(args[0])) {
      throw new Error('Invalid input');
    }
    return originalMethod.apply(this, args);
  };

  return descriptor;
}

Ce décorateur vérifie la validité de l'argument avant d'appeler la méthode.

Type Fonctionnalité Exemple
Classe Modifie la classe entière @Injectable / @Service
Méthode Intercepte les appels de méthode @Log
Propriété Affecte les propriétés de classe @Observable

Créer des décorateurs de classe

Mise en œuvre des décorateurs de classe

Créer un décorateur de classe consiste à définir une fonction qui reçoit la classe cible. À l'intérieur, vous pouvez ajouter des propriétés statiques ou des méthodes au prototype, ou enregistrer la classe dans un conteneur d'injection. Voici un exemple simple qui marque une classe comme service :

function Service(target: any) {
  target.isService = true;
  target.getServiceName = function() {
    return this.name || this.constructor?.name;
  };
}

Usage :

@Service
class UserService {
  constructor() {}
}

console.log((UserService as any).isService); // true

Les décorateurs de classe sont souvent utilisés dans des frameworks comme Angular (decorators built-in) ou NestJS pour déclarer des services, contrôleurs et modules.

Utilisation des décorateurs de méthode et de propriété

Définition et fonctionnement

Les décorateurs de méthode modifient le comportement d'une méthode sans changer son code source. Par exemple, on peut ajouter une journalisation ou une surveillance d'erreurs centralisée. Les décorateurs de propriété permettent de valider ou de transformer une valeur lors de son assignation.

  • Journalisation des appels de méthode
  • Validation des valeurs de propriété
  • Ajout de fonctionnalités transversales (AOP)
  • Mise en cache des résultats

Décorateur de méthode pour la journalisation (TypeScript) :

function LogMethod(target: any, propertyKey: string, descriptor: PropertyDescriptor) {
  const originalMethod = descriptor.value;

  descriptor.value = function(...args: any[]) {
    console.log(`Appel de ${propertyKey} avec arguments: ${JSON.stringify(args)}`);
    return originalMethod.apply(this, args);
  };

  return descriptor;
}

Décorateur de propriété simple pour validation :

function MinLength(length: number) {
  return function(target: any, propertyKey: string) {
    let value: string;

    const getter = function() {
      return value;
    };

    const setter = function(newVal: string) {
      if (newVal.length < length) {
        throw new Error(`${propertyKey} must be at least ${length} characters`);
      }
      value = newVal;
    };

    Object.defineProperty(target, propertyKey, {
      get: getter,
      set: setter,
      enumerable: true,
      configurable: true,
    });
  };
}

Cas d'utilisation pratiques des décorateurs

Exemples concrets

Dans un projet de gestion des utilisateurs, nous avons utilisé les décorateurs pour valider les données d'entrée lors de l'ajout de nouveaux utilisateurs. En appliquant un décorateur de propriété, j'ai pu garantir que les adresses e-mail soient uniques avant de les enregistrer dans la base de données (vérification côté service avant INSERT). Cela a réduit les erreurs d'enregistrement.

Un autre exemple concerne la mise en cache des résultats de méthodes coûteuses. Ci-dessous un décorateur de mise en cache synchrone :

function CacheResults(target: any, propertyKey: string, descriptor: PropertyDescriptor) {
  const originalMethod = descriptor.value;
  const cache: { [key: string]: any } = {};

  descriptor.value = function(...args: any[]) {
    const key = JSON.stringify(args);
    if (cache.hasOwnProperty(key)) {
      return cache[key];
    }
    const result = originalMethod.apply(this, args);
    cache[key] = result;
    return result;
  };

  return descriptor;
}

Si la méthode est asynchrone (retourne une Promise), adaptez le décorateur pour stocker et renvoyer la Promise afin d'éviter des doublons de calcul :

function CacheAsyncResults(target: any, propertyKey: string, descriptor: PropertyDescriptor) {
  const originalMethod = descriptor.value;
  const cache: { [key: string]: Promise<any> } = {};

  descriptor.value = function(...args: any[]) {
    const key = JSON.stringify(args);
    if (cache[key]) {
      return cache[key];
    }
    const promise = originalMethod.apply(this, args);
    cache[key] = promise;
    return promise;
  };

  return descriptor;
}

Ces techniques sont utiles dans des services Node.js basés sur Express ou NestJS (par exemple, pour des endpoints qui font des calculs ou des appels externes coûteux).

Meilleures pratiques et considérations de performance

Optimisation des décorateurs

Pour maximiser l'efficacité des décorateurs en TypeScript 5.5, il est crucial de comprendre leur impact sur les performances et la sécurité :

  • Évitez d'appliquer plusieurs décorateurs sur des méthodes critiques en termes de performance.
  • Préférez des décorateurs simples et testables; séparez la logique (ex. : validation vs. journalisation).
  • Si vous enregistrez des métadonnées, limitez leur taille et évitez d'ajouter des structures cycliques.
  • Pour les décorateurs asynchrones, gérez correctement les Promises et les erreurs pour éviter des fuites mémoire.

Sécurité et dépannage

  • Ne mettez jamais d'informations sensibles (clés API, mots de passe) dans les métadonnées ou logs produits par des décorateurs.
  • Ajoutez des tests unitaires ciblant les décorateurs (moquez la cible et vérifiez le comportement modifié).
  • Pour le dépannage, activez un logger conditionnel (par variable d'environnement) afin d'éviter la surcharge de logs en production.
  • Surveillez l'empreinte mémoire si votre décorateur met en cache des résultats; utilisez des TTL ou LRU pour limiter la taille.

Exemple de décorateur pour mesurer le temps d'exécution (utilisable en dev) :

function LogExecutionTime(target: any, propertyKey: string, descriptor: PropertyDescriptor) {
  const originalMethod = descriptor.value;

  descriptor.value = function(...args: any[]) {
    const label = `${target.constructor.name}.${propertyKey}`;
    console.time(label);
    try {
      const result = originalMethod.apply(this, args);
      if (result && typeof result.then === 'function') {
        // Promise: measure until resolution
        return result.then((res: any) => {
          console.timeEnd(label);
          return res;
        }).catch((err: any) => {
          console.timeEnd(label);
          throw err;
        });
      }
      console.timeEnd(label);
      return result;
    } catch (err) {
      console.timeEnd(label);
      throw err;
    }
  };

  return descriptor;
}

Points Clés à Retenir

  • Les décorateurs en TypeScript permettent d'ajouter des métadonnées et de modifier le comportement des classes ou méthodes sans changer leur code source.
  • Utiliser les décorateurs de méthodes peut améliorer la lisibilité et la maintenabilité du code en séparant les préoccupations.
  • Les décorateurs peuvent être utilisés pour la validation, la mise en cache et l'authentification; attention à la performance et à la sécurité.
  • TypeScript 5.5 apporte des améliorations et une meilleure ergonomie pour écrire des décorateurs robustes et testables.

Questions Fréquentes

Comment puis-je créer un décorateur de méthode en TypeScript ?
Créez une fonction qui prend trois arguments : la cible, le nom de la méthode et la description (PropertyDescriptor). Exemple court : function log(target, propertyKey, descriptor) { console.log(propertyKey + ' a été appelé'); }. Appliquez ensuite le décorateur avec @log au-dessus de la méthode.
Les décorateurs sont-ils compatibles avec JavaScript ?
Les décorateurs ne sont pas (encore) standardisés en JavaScript, mais ils sont utilisés via TypeScript et des outils comme Babel. En production Node.js/TypeScript, utilisez la configuration officielle du compilateur (tsconfig) et vérifiez la compatibilité avec votre pipeline de build.
Quels sont les avantages d'utiliser des décorateurs pour la validation ?
Ils centralisent la logique de validation, la rendent réutilisable et évitent la duplication de code. En plaçant la validation au niveau des propriétés ou des méthodes, vous améliorez la lisibilité et la maintenabilité.
Comment gérer les erreurs dans un décorateur en TypeScript ?
Enveloppez la méthode cible dans un try/catch (ou gérez la rejection pour les Promises). Loggez l'erreur avec un identifiant contextualisé et, selon le cas, rethrow pour laisser la couche supérieure gérer l'exception.

Conclusion

En intégrant les décorateurs dans vos projets TypeScript, vous pouvez améliorer la structure et la clarté de votre code. Par exemple, l'utilisation de décorateurs pour gérer l'authentification ou la validation réduit la duplication et centralise la logique transversale. Commencez par des décorateurs simples, testables et limités aux zones non critiques en performance, puis étendez progressivement.

Les décorateurs restent un outil puissant pour architecturer des applications modulaires. Expérimentez avec des patterns comme cache-aspect, logging-aspect ou validation-aspect, et ajoutez des tests unitaires pour garantir la robustesse.