Decorators in TypeScript

Decorators in TypeScript

Dit artikel legt decorators in TypeScript uit.

YouTube Video

Decorators in TypeScript

TypeScript-decorators zijn een mechanisme om aanvullende functionaliteit of gedrag toe te voegen aan klassen, methoden, toegangselementen, eigenschappen of parameters. Decorators zijn een krachtig hulpmiddel om de leesbaarheid en herbruikbaarheid van code te verbeteren.

Basisprincipes van Decorators

Een decorator is een functie die aanvullende functionaliteit injecteert in een klasse of klasseleden. Decorators werden geïntroduceerd in TypeScript 1.5 en zijn ook voorgesteld voor de ECMAScript-standaard.

1{
2  "compilerOptions": {
3    "experimentalDecorators": true
4  }
5}
  • Om decorators te gebruiken, moet je de optie experimentalDecorators inschakelen in het tsconfig.json-bestand.

Soorten Decorators

In TypeScript kun je de volgende vijf decorators gebruiken.

  • Klasse-decorator Een decorator die op een klasse wordt toegepast.
  • Methode-decorator Een decorator die op een methode van een klasse wordt toegepast.
  • Accessor-decorator Een decorator die wordt toegepast op een getter of setter van een klasse-eigenschap.
  • Eigenschap-decorator Een decorator die op een eigenschap van een klasse wordt toegepast.
  • Parameter-decorator Een decorator die op een parameter van een methode wordt toegepast.

Klasse Decorator

Klasse-decorators zijn decorators die worden toegepast op klassen. Klasse-decorators worden direct boven de klasse-definitie geschreven en hebben toegang tot de klasseconstructor. Ze worden voornamelijk gebruikt om het gedrag van een klasse te wijzigen of metadata toe te voegen.

 1function Logger(constructor: Function) {
 2    console.log(`Class ${constructor.name} is being constructed`);
 3}
 4
 5@Logger
 6class Person {
 7    constructor(public name: string) {}
 8}
 9
10const person = new Person('John');
11// Output: Class Person is being constructed

In dit voorbeeld wordt de Logger decorator toegepast op de klasse en wordt er een bericht weergegeven in de console wanneer de klasse wordt geïnitialiseerd.

Methode Decorator

Methode-decorators worden toegepast op klassemethode en kunnen method oproepen en gedrag veranderen. Een methode-decorator neemt drie argumenten.

  1. Het prototype van de klasse
  2. De naam van de methode
  3. De eigenschapdescriptor van de methode
 1function LogExecutionTime(target: any, propertyKey: string, descriptor: PropertyDescriptor) {
 2    const originalMethod = descriptor.value;
 3
 4    descriptor.value = function (...args: any[]) {
 5        console.time(propertyKey);
 6        const result = originalMethod.apply(this, args);
 7        console.timeEnd(propertyKey);
 8        return result;
 9    };
10}
11
12class MathOperations {
13  @LogExecutionTime
14  add(a: number, b: number): number {
15    return a + b;
16  }
17}
18
19const math = new MathOperations();
20math.add(2, 3);
21// Output: add: 0.000ms (execution time is displayed)

In dit voorbeeld wordt de LogExecutionTime decorator toegepast op de methode, en de uitvoeringstijd van de methode wordt gelogd.

Toegangsdecorator

Toegangsdecorators worden toegepast op getter of setter van klasse-eigenschappen. Ze zijn nuttig om gedrag toe te voegen bij het wijzigen van eigenschapswaarden.

 1function LogAccess(target: any, propertyKey: string, descriptor: PropertyDescriptor) {
 2    const originalGet = descriptor.get;
 3    const originalSet = descriptor.set;
 4
 5    if (originalGet) {
 6        descriptor.get = function () {
 7            console.log(`Getter called for ${propertyKey}`);
 8            return originalGet.call(this);
 9        };
10    }
11
12    if (originalSet) {
13        descriptor.set = function (value: any) {
14            console.log(`Setter called for ${propertyKey} with value: ${value}`);
15            originalSet.call(this, value);
16        };
17    }
18}
19
20class Car {
21    private _speed: number = 0;
22
23    @LogAccess
24    get speed() {
25        return this._speed;
26    }
27
28    set speed(value: number) {
29        this._speed = value;
30    }
31}
32
33const car = new Car();
34car.speed = 120;               // Setter called for speed with value: 120
35console.log(car.speed);       // Getter called for speed → 120

In dit voorbeeld wordt een accessordecorator gebruikt om output te loggen wanneer de getter en setter worden aangeroepen.

Eigenschapsdecorator

Eigenschapsdecorators worden toegepast op klasse-eigenschappen, maar kunnen de waarde of het gedrag van de eigenschap niet direct wijzigen. Ze worden gebruikt om metadata van eigenschappen te verkrijgen.

 1function Readonly(target: any, propertyKey: string) {
 2    Object.defineProperty(target, propertyKey, {
 3        writable: false
 4    });
 5}
 6
 7class Book {
 8    @Readonly
 9    title: string = "TypeScript Guide";
10}
11
12const book = new Book();
13book.title = "New Title"; // Error: Cannot assign to read only property 'title'

In dit voorbeeld wordt de Readonly decorator toegepast op de title eigenschap, en wordt de eigenschap alleen-lezen gemaakt.

Parameterdecorator

Parameterdecorators worden toegepast op de parameters van een methode. Ze worden meestal gebruikt om metadata op te slaan of parameters te valideren. Decorators accepteren drie argumenten.

  1. Het prototype van de klasse
  2. De naam van de methode
  3. Parameterindex
 1function LogParameter(target: any, propertyKey: string, parameterIndex: number) {
 2    console.log(`Parameter at index ${parameterIndex} in method ${propertyKey} was decorated.`);
 3}
 4
 5class User {
 6    greet(@LogParameter message: string) {
 7        console.log(message);
 8    }
 9}
10
11const user = new User();
12user.greet('Hello!');
13// Output: Parameter at index 0 in method greet was decorated.

In dit voorbeeld wordt de LogParameter decorator toegepast op de eerste parameter van de greet methode, en wanneer de methode wordt aangeroepen, wordt gelogd dat de parameter is gedecoreerd.

Praktische voorbeelden van decorators

Decorators worden veel gebruikt in frameworks zoals Angular, vooral voor dependency injection en metadatadefinitie. Gebruik bijvoorbeeld de @Component decorator om Angular-componenten zoals hieronder te definiëren.

1@Component({
2    selector: 'app-root',
3    template: '<h1>Hello World</h1>',
4})
5export class AppComponent {}

Decorators worden dus vaak gebruikt als kernonderdelen van frameworks en bibliotheken, waardoor code beknopt en duidelijk blijft.

Samenvatting van decorators

TypeScript decorators zijn krachtige hulpmiddelen die flexibel functionaliteit toevoegen aan klassen, methoden en eigenschappen. Het gebruik van aangepaste decorators verbetert de onderhoudbaarheid en herbruikbaarheid van de code en maakt verdere abstractie mogelijk. Decorators spelen een belangrijke rol in frameworks zoals Angular en NestJS, en ze begrijpen helpt om diepgaand te begrijpen hoe deze frameworks werken.

Je kunt het bovenstaande artikel volgen met Visual Studio Code op ons YouTube-kanaal. Bekijk ook het YouTube-kanaal.

YouTube Video