Come utilizzare i decoratori in TypeScript

I decoratori in TypeScript sono una potente funzionalità che consente agli sviluppatori di aggiungere funzionalità extra a classi, metodi, proprietà e parametri. Forniscono un modo per modificare il comportamento del codice esistente senza cambiarne la struttura effettiva. Questa guida spiegherà come utilizzare i decoratori in TypeScript con esempi facili da seguire.

Cosa sono i decoratori?

I decoratori sono funzioni speciali che possono essere applicate a classi, metodi, proprietà o parametri. Vengono richiamati in fase di esecuzione e consentono agli sviluppatori di annotare e modificare il codice in modo dichiarativo. Per abilitare i decoratori in un progetto TypeScript, il flag experimentalDecorators deve essere impostato su true nel file tsconfig.json.

Abilitazione dei decoratori in TypeScript

Per usare i decoratori, il compilatore TypeScript deve essere configurato per riconoscerli. Questo può essere fatto impostando il flag experimentalDecorators su true nel file tsconfig.json.

{
  "compilerOptions": {
    "target": "ES6",
    "experimentalDecorators": true
  }
}

Una volta abilitati, i decoratori possono essere utilizzati in tutto il progetto.

Creazione di un decoratore di classe

Un decoratore di classe viene applicato a una dichiarazione di classe e può essere utilizzato per modificare o sostituire una definizione di classe. I decoratori di classe vengono dichiarati appena sopra la classe che decorano, utilizzando il simbolo @.

function LogClass(target: Function) {
  console.log(`Class ${target.name} is created.`);
}

@LogClass
class Person {
  constructor(public name: string) {}
}

const person = new Person('Alice');

In questo esempio, il decoratore LogClass registra un messaggio quando viene creata la classe Person. Il decoratore è definito come una funzione che accetta un singolo argomento: il costruttore della classe che viene decorata.

Decoratori di metodo

I decoratori di metodo vengono applicati ai metodi all'interno di una classe. Consentono agli sviluppatori di intercettare le chiamate di metodo, modificarne il comportamento o eseguire operazioni aggiuntive prima o dopo l'esecuzione del metodo.

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

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

  return descriptor;
}

class Calculator {
  @LogMethod
  add(a: number, b: number): number {
    return a + b;
  }
}

const calc = new Calculator();
calc.add(2, 3);

Qui, il decoratore LogMethod registra il nome del metodo e i suoi argomenti ogni volta che viene chiamato il metodo add. Incapsula il metodo originale in una nuova funzione che esegue la registrazione prima di delegare al metodo originale.

Decoratori di proprietà

I decoratori di proprietà sono usati per osservare o modificare il comportamento delle proprietà di classe. A differenza dei decoratori di metodo, non hanno accesso al valore della proprietà stessa, ma possono aggiungere metadati alle proprietà.

function ReadOnly(target: Object, propertyKey: string) {
  Object.defineProperty(target, propertyKey, {
    writable: false
  });
}

class Book {
  @ReadOnly
  title: string = 'TypeScript Guide';
}

const myBook = new Book();
myBook.title = 'New Title'; // This will cause an error in strict mode

In questo esempio, il decoratore ReadOnly viene applicato alla proprietà title della classe Book, rendendola di sola lettura impostando writable su false.

Decoratori dei parametri

I decoratori di parametri vengono utilizzati per annotare o modificare i parametri del metodo. Ricevono tre argomenti: l'oggetto di destinazione, il nome del metodo e l'indice del parametro.

function LogParameter(target: Object, propertyKey: string, parameterIndex: number) {
  console.log(`Parameter in position ${parameterIndex} at ${propertyKey} method is decorated.`);
}

class UserService {
  greet(@LogParameter message: string): void {
    console.log(message);
  }
}

const userService = new UserService();
userService.greet('Hello, TypeScript!');

In questo esempio, il decoratore LogParameter viene applicato al parametro message del metodo greet nella classe UserService. Il decoratore registra le informazioni sul parametro decorato.

Conclusione

I decoratori in TypeScript offrono un modo potente per migliorare la funzionalità del codice senza alterarne la struttura. Sfruttando decoratori di classe, metodo, proprietà e parametro, gli sviluppatori possono facilmente aggiungere funzionalità riutilizzabili nei loro progetti. Con gli esempi forniti in questa guida, è facile iniziare a usare i decoratori in TypeScript.