"Si un ouvrier veut bien faire son travail, il doit d'abord affûter ses outils." - Confucius, "Les Entretiens de Confucius. Lu Linggong"
Page de garde > La programmation > Comprendre les décorateurs dans TypeScript : une approche fondée sur les premiers principes

Comprendre les décorateurs dans TypeScript : une approche fondée sur les premiers principes

Publié le 2024-11-01
Parcourir:956

Understanding Decorators in TypeScript: A First-Principles Approach

Les décorateurs dans TypeScript fournissent un mécanisme puissant pour modifier le comportement des classes, des méthodes, des propriétés et des paramètres. Bien qu’ils puissent sembler une commodité moderne, les décorateurs sont ancrés dans le modèle de décorateur bien établi que l’on trouve dans la programmation orientée objet. En faisant abstraction des fonctionnalités courantes telles que la journalisation, la validation ou le contrôle d'accès, les décorateurs permettent aux développeurs d'écrire un code plus propre et plus maintenable.

Dans cet article, nous explorerons les décorateurs à partir des principes de base, décomposerons leurs fonctionnalités de base et les implémenterons à partir de zéro. En cours de route, nous examinerons quelques applications du monde réel qui mettent en valeur l'utilité des décorateurs dans le développement quotidien de TypeScript.

Qu'est-ce qu'un décorateur ?

Dans TypeScript, un décorateur est simplement une fonction qui peut être attachée à une classe, une méthode, une propriété ou un paramètre. Cette fonction est exécutée au moment de la conception, vous donnant la possibilité de modifier le comportement ou la structure du code avant son exécution. Les décorateurs permettent la méta-programmation, nous permettant d'ajouter des fonctionnalités supplémentaires sans modifier la logique d'origine.

Commençons par un exemple simple de décorateur de méthode qui enregistre lorsqu'une méthode est appelée :

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

  descriptor.value = function (...args: any[]) {
    console.log(`Calling ${propertyKey} with arguments: ${args}`);
    return originalMethod.apply(this, args);
  };

  return descriptor;
}

class Example {
  @log
  greet(name: string) {
    return `Hello, ${name}`;
  }
}

const example = new Example();
example.greet('John');

Ici, le décorateur de journal encapsule la méthode greet, en enregistrant son invocation et ses paramètres avant de l'exécuter. Ce modèle est utile pour séparer les préoccupations transversales telles que la journalisation de la logique de base.

Comment travaillent les décorateurs

Les décorateurs dans TypeScript sont des fonctions qui récupèrent les métadonnées liées à l'élément qu'ils décorent. Sur la base de ces métadonnées (comme les prototypes de classe, les noms de méthodes ou les descripteurs de propriétés), les décorateurs peuvent modifier le comportement ou même remplacer l'objet décoré.

Types de décorateurs

Les décorateurs peuvent être appliqués à différentes cibles, chacune ayant des objectifs différents :

  • Class Decorators : Une fonction qui reçoit le constructeur de la classe.
function classDecorator(constructor: Function) {
  // Modify or extend the class constructor or prototype
}
  • Method Decorators : Une fonction qui reçoit l'objet cible, le nom de la méthode et le descripteur de la méthode.
function methodDecorator(target: any, propertyKey: string, descriptor: PropertyDescriptor) {
  // Modify the method's descriptor
}
  • Property Decorators : Une fonction qui reçoit l'objet cible et le nom de la propriété.
function propertyDecorator(target: any, propertyKey: string) {
  // Modify the behavior of the property
}
  • Parameter Decorators : Une fonction qui reçoit la cible, le nom de la méthode et l'index du paramètre.
function parameterDecorator(target: any, propertyKey: string, parameterIndex: number) {
  // Modify or inspect the method's parameter
}

Passer des arguments aux décorateurs

L'une des fonctionnalités les plus puissantes des décorateurs est leur capacité à accepter les arguments, vous permettant ainsi de personnaliser leur comportement. Par exemple, créons un décorateur de méthode qui enregistre les appels de méthode de manière conditionnelle en fonction d'un argument.

function logConditionally(shouldLog: boolean) {
  return function (target: any, propertyKey: string, descriptor: PropertyDescriptor) {
    const originalMethod = descriptor.value;

    descriptor.value = function (...args: any[]) {
      if (shouldLog) {
        console.log(`Calling ${propertyKey} with arguments: ${args}`);
      }
      return originalMethod.apply(this, args);
    };

    return descriptor;
  };
}

class Example {
  @logConditionally(true)
  greet(name: string) {
    return `Hello, ${name}`;
  }
}

const example = new Example();
example.greet('TypeScript Developer');

En passant true au décorateur logConditionally, nous nous assurons que la méthode enregistre son exécution. Si nous passons false, la journalisation est ignorée. Cette flexibilité est essentielle pour rendre les décorateurs polyvalents et réutilisables.

Applications réelles des décorateurs

Les décorateurs ont trouvé une utilisation pratique dans de nombreuses bibliothèques et frameworks. Voici quelques exemples notables qui illustrent comment les décorateurs rationalisent des fonctionnalités complexes :

  • Validation dans le validateur de classe : dans les applications basées sur les données, la validation est cruciale. Le package class-validator utilise des décorateurs pour simplifier le processus de validation des champs dans les classes TypeScript.
import { IsEmail, IsNotEmpty } from 'class-validator';

class User {
  @IsNotEmpty()
  name: string;

  @IsEmail()
  email: string;
}

Dans cet exemple, les décorateurs @IsEmail et @IsNotEmpty garantissent que le champ e-mail est une adresse e-mail valide et que le champ nom n'est pas vide. Ces décorateurs gagnent du temps en éliminant le besoin d'une logique de validation manuelle.

  • Mappage objet-relationnel avec TypeORM : les décorateurs sont largement utilisés dans les frameworks ORM comme TypeORM pour mapper les classes TypeScript aux tables de base de données. Ce mappage est effectué de manière déclarative à l'aide de décorateurs.
import { Entity, Column, PrimaryGeneratedColumn } from 'typeorm';

@Entity()
class User {
  @PrimaryGeneratedColumn()
  id: number;

  @Column()
  name: string;

  @Column()
  email: string;
}

Ici, @Entity, @Column et @PrimaryGeneratedColumn définissent la structure de la table User. Ces décorateurs éliminent la complexité de la création de tables SQL, rendant le code plus lisible et maintenable.

  • Injection de dépendance angulaire : dans Angular, les décorateurs jouent un rôle central dans la gestion des services et des composants. Le décorateur @Injectable marque une classe comme un service pouvant être injecté dans d'autres composants ou services.
@Injectable({
  providedIn: 'root',
})
class UserService {
  constructor(private http: HttpClient) {}
}

Le décorateur @Injectable dans ce cas signale au système d'injection de dépendances d'Angular que le UserService doit être fourni globalement. Cela permet une intégration transparente des services dans l'ensemble de l'application.

Implémenter vos propres décorateurs : une panne

Les décorateurs ne sont, à la base, que des fonctions. Décomposons le processus de création de décorateurs à partir de zéro :

Décorateur de classe

Un décorateur de classe reçoit le constructeur de la classe et peut être utilisé pour modifier le prototype de classe ou même remplacer le constructeur.

function AddTimestamp(constructor: Function) {
  constructor.prototype.timestamp = new Date();
}

@AddTimestamp
class MyClass {
  id: number;
  constructor(id: number) {
    this.id = id;
  }
}

const instance = new MyClass(1);
console.log(instance.timestamp);  // Outputs the current timestamp

Méthode Décorateur

Un décorateur de méthode modifie le descripteur de méthode, vous permettant de modifier le comportement de la méthode elle-même.

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

  descriptor.value = function (...args: any[]) {
    const start = performance.now();
    const result = originalMethod.apply(this, args);
    const end = performance.now();
    console.log(`${propertyKey} executed in ${end - start}ms`);
    return result;
  };

  return descriptor;
}

class Service {
  @logExecutionTime
  execute() {
    // Simulate work
    for (let i = 0; i 



Décorateur immobilier

Un décorateur de propriété vous permet d'intercepter l'accès et la modification d'une propriété, ce qui peut être utile pour suivre les modifications.

function trackChanges(target: any, propertyKey: string) {
  let value = target[propertyKey];

  const getter = () => value;
  const setter = (newValue: any) => {
    console.log(`${propertyKey} changed from ${value} to ${newValue}`);
    value = newValue;
  };

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

class Product {
  @trackChanges
  price: number;

  constructor(price: number) {
    this.price = price;
  }
}

const product = new Product(100);
product.price = 200;  // Logs the change

Conclusion

Les décorateurs de TypeScript vous permettent d'abstraire et de réutiliser des fonctionnalités de manière propre et déclarative. Que vous travailliez avec la validation, les ORM ou l'injection de dépendances, les décorateurs aident à réduire le passe-partout et à garder votre code modulaire et maintenable. Comprendre comment ils fonctionnent à partir des premiers principes permet d'exploiter plus facilement leur plein potentiel et de créer des solutions personnalisées adaptées à votre application.

En examinant de plus près la structure et les applications réelles des décorateurs, vous avez maintenant vu comment ils peuvent simplifier des tâches de codage complexes et rationaliser le code dans divers domaines.

Déclaration de sortie Cet article est reproduit sur: https://dev.to/curious_tinkerer/udgerstanding-decorators-in-typescript-a-first-principles-pproach-2n3h?1 s'il y a une contrefaçon, veuillez contacter [email protected] pour le supprimer.
Dernier tutoriel Plus>

Clause de non-responsabilité: Toutes les ressources fournies proviennent en partie d'Internet. En cas de violation de vos droits d'auteur ou d'autres droits et intérêts, veuillez expliquer les raisons détaillées et fournir une preuve du droit d'auteur ou des droits et intérêts, puis l'envoyer à l'adresse e-mail : [email protected]. Nous nous en occuperons pour vous dans les plus brefs délais.

Copyright© 2022 湘ICP备2022001581号-3