Maison > interface Web > js tutoriel > Comprendre les décorateurs dans TypeScript : une approche basée sur les premiers principes

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

DDD
Libérer: 2024-09-21 06:29:02
original
1053 Les gens l'ont consulté

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 ?

En 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');
Copier après la connexion

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
}
Copier après la connexion
  • 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
}
Copier après la connexion
  • 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
}
Copier après la connexion
  • 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
}
Copier après la connexion

Passer des arguments aux décorateurs

L'une des caractéristiques les plus puissantes des décorateurs est leur capacité à accepter les arguments, vous permettant 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');
Copier après la connexion

En passant true au décorateur logConditionally, nous nous assurons que la méthode journalise 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 class-validator : 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;
}
Copier après la connexion

Dans cet exemple, les décorateurs @IsEmail et @IsNotEmpty s'assurent que le champ email 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;
}
Copier après la connexion

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) {}
}
Copier après la connexion

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 :

Class Decorator

A class decorator receives the constructor of the class and can be used to modify the class prototype or even replace the constructor.

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
Copier après la connexion

Method Decorator

A method decorator modifies the method descriptor, allowing you to alter the behavior of the method itself.

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 < 1e6; i++) {}
  }
}

const service = new Service();
service.execute();  // Logs the execution time
Copier après la connexion

Property Decorator

A property decorator allows you to intercept property access and modification, which can be useful for tracking changes.

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
Copier après la connexion

Conclusion

Decorators in TypeScript allow you to abstract and reuse functionality in a clean, declarative manner. Whether you're working with validation, ORMs, or dependency injection, decorators help reduce boilerplate and keep your code modular and maintainable. Understanding how they work from first principles makes it easier to leverage their full potential and craft custom solutions tailored to your application.

By taking a deeper look at the structure and real-world applications of decorators, you've now seen how they can simplify complex coding tasks and streamline code across various domains.

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

source:dev.to
Déclaration de ce site Web
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn
Tutoriels populaires
Plus>
Derniers téléchargements
Plus>
effets Web
Code source du site Web
Matériel du site Web
Modèle frontal