Decoratori di TypeScript: classi, metodi e proprietà
I decoratori in TypeScript sono un modo pratico e semplice per assegnare funzionalità aggiuntive agli oggetti senza modificare il codice sorgente. È possibile utilizzarli su classi, metodi, proprietà, funzioni di accesso e parametri, così da accedere ad annotazioni e metadati.
Che cosa sono i decoratori di TypeScript e a cosa servono?
Il principio dei decoratori di TypeScript non è del tutto nuovo. In altri linguaggi di programmazione sono disponibili funzionalità simili, ad esempio gli attributi in C#, i decoratori in Python o le annotazioni in Java. Si tratta di possibilità per espandere le funzionalità di un oggetto senza modificare il codice sorgente. Anche TypeScript sfrutta questo principio già da tempo. Anche se la maggior parte dei browser non supporta (ancora) i decoratori di TypeScript, vale comunque la pena sperimentare questo approccio e le sue possibilità. A partire dalla versione 5.0, l’uso dei decoratori è stato notevolmente semplificato.
I decoratori di TypeScript sono utilizzati per creare annotazioni e metadati aggiuntivi per le classi di TypeScript e per aggiungere elementi. Oltre alle classi è possibile modificare anche metodi, proprietà, metodi di accesso e parametri. Questi ultimi possono essere verificati ed è possibile richiamarne i valori. Anche questa è una grande differenza tra i decoratori di TypeScript e il loro equivalente per JavaScript.
- Massima sicurezza dei tuoi dati
- Strumenti di collaborazione per lavorare in team
- Aggiornamenti automatici
Sintassi e funzionamento dei decoratori
Quando aggiungi i decoratori di TypeScript a un oggetto, in realtà stai richiamando una funzione che può essere eseguita senza modificare il codice sorgente. Ciò aumenta la funzionalità e preserva comunque la chiarezza del codice. La sintassi di base si presenta così:
@nomeDecoratore
typescriptÈ possibile creare questa funzione con due o tre parametri. La sintassi per la funzione con tre parametri si presenta simile a questa:
function FunzioneDecoratore(target: any, propertyKey: string, descriptor: PropertyDescriptor) {
console.log(`Decorating ${propertyKey} of class ${target.constructor.name}`);
}
class MyClass {
@FunzioneDecoratore
myMethod() {
}
}
typescriptI singoli componenti dei decoratori di TypeScript sono costituiti da questi elementi:
target
:target
indica l’oggetto a cui è stato assegnato il decoratorepropertyKey
:propertyKey
è una stringa contenente il nome della classe a cui è stato assegnato un decoratore; tra le varie opzioni, è possibile inserire metodi o proprietàdescriptor
: indescriptor
è possibile inserire ulteriori informazioni sull’oggetto a cui si applica il decoratore; le proprietà possibili sonovalue
,writable
,enumerable
oconfigurable
.
La sintassi dei decoratori in TypeScript con due parametri è la seguente:
function FunzioneDecoratore(target: any) {
console.log(`Decorating ${target.name}`);
}
@FunzioneDecoratore
class MyClass {
}
typescriptIn questo caso, i decoratori di TypeScript sono stati applicati a una classe.
I diversi tipi di decoratori
Esistono diversi tipi di decoratori di TypeScript, ciascuno dotato di caratteristiche particolari e che descriveremo in dettaglio più avanti nell’articolo:
- Decoratori di classe
- Decoratori di metodo
- Decoratori di proprietà
- Decoratori di accessor
- Decoratori di parametri
Decoratori di TypeScript per classi
I decoratori di TypeScript ti permettono di personalizzare le proprietà di una classe e modificarne il costruttore, i metodi o le proprietà. Come primo parametro accettano il costruttore non appena si “decora” la classe con una funzione. Quello che segue è un codice di esempio in cui lavoriamo con un elenco di clienti. Qui si possono notare alcune proprietà private e altre pubbliche:
class Clienti {
private static userType: string = "Generic";
private _email: string;
public nomecliente: string;
public via: string = "";
public località: string = "";
public paese: string = "";
constructor(nomecliente: string, email: string) {
this.nomecliente = nomecliente;
this._email = email;
}
Static get userType() {
return Clienti.userType;
}
get email() {
return this._email;
}
set email(emailnuova: string) {
this._email = emailnuova;
}
indirizzo(): string {
return `${this.via}\n${this.località}\n${this.paese}`;
}
}
const p = new Clienti("esempiocliente", "nome@esempio.com");
p.via = "Via Garibaldi 2";
p.località = "Roma";
typescriptNel passaggio successivo utilizzeremo quindi i decoratori di TypeScript per aggiungere funzioni supplementari che tuttavia non vanno poi a modificare il codice sorgente. Aggiungiamo quindi il decoratore @frozen
per la classe “Clienti”. Questa funzione fa sì che gli oggetti non possano essere modificati successivamente. Per alcune proprietà utilizziamo @required
per dare istruzioni esplicite all’input. Utilizziamo inoltre @enumerable
per gli elenchi e @deprecated
per gli input obsoleti. Per prima cosa ci occupiamo della definizione dei decoratori:
function frozen(constructor: Function) {
Object.freeze(constructor);
Object.freeze(constructor.prototype);
}
function required(target: any, propertyKey: string) {
// Logica per il decoratore Required
}
function enumerable(value: boolean) {
return function (target: any, propertyKey: string, descriptor: PropertyDescriptor) {
descriptor.enumerable = value;
};
}
function deprecated(target: any, propertyKey: string, descriptor: PropertyDescriptor) {
console.warn(`The method ${propertyKey} is deprecated.`);
}
typescriptDopo l’utilizzo dei decoratori di TypeScript, il codice finale si presenta così:
@frozen
class Clienti {
private static userType: string = "Generic";
@required
private _email: string;
@required
public nomecliente: string;
public via: string = "";
public località: string = "";
public paese: string = "";
constructor(nomecliente: string, email: string) {
this.nomecliente = nomecliente;
this._email = email;
}
@enumerable(false)
get userType() {
return Clienti.userType;
}
get email() {
return this._email;
}
set email(emailnuova: string) {
this._email = emailnuova;
}
@deprecated
indirizzo(): string {
return `${this.via}\n${this.località}\n${this.paese}`;
}
}
const p = new Clienti("esempiocliente", "nome@esempio.com");
p.via = "Via Garibaldi, 2";
p.località = "Roma";
typescriptDecoratori di TypeScript per metodi
È possibile utilizzare i decoratori di TypeScript anche per i metodi. Fanno eccezione solo i file di dichiarazione, l’overloading e la classe “declare”. Nell’esempio seguente utilizziamo @enumerable
come decoratore per il metodo getName
nella classe “Person”:
const enumerable = (value: boolean) => {
return (target: any, propertyKey: string, propertyDescriptor: PropertyDescriptor) => {
propertyDescriptor.enumerable = value;
}
}
class Person {
nome: string = "Giulia"
cognome: string = "Rossi"
@enumerable(true)
getName () {
return `${this.nome} ${this.cognome}`;
}
}
typescriptDecoratori di TypeScript per proprietà
I decoratori di TypeScript per le proprietà di una classe (decoratori di proprietà) possono avere due parametri: la funzione costruttore della classe e il nome della proprietà. Nell’esempio seguente utilizziamo il decoratore per restituire il nome di una proprietà (in questo caso il nome del cliente):
const printPropertyName = (target: any, propertyName: string) => {
console.log(propertyName);
};
class Clienti {
@printPropertyName
name: string = "Giulia";
}
typescriptDecoratori di TypeScript per funzioni di accesso
I decoratori di accessor funzionano secondo un principio molto simile ai decoratori di proprietà. Rispetto a questi ultimi hanno un terzo parametro aggiuntivo. Nel nostro esempio, questo parametro è il descrittore di proprietà per un cliente. A questo punto, se si restituisce un valore utilizzando il decoratore di accessor, il valore diventa il nuovo descrittore della proprietà. Il codice seguente cambia quindi il valore booleano (“true” o “false”) di enumerable
. Il nostro punto di partenza è il seguente:
const enumerable = (value: boolean) => {
return (target: any, propertyKey: string, descriptor: PropertyDescriptor) => {
descriptor.enumerable = value;
}
}
typescriptIl decoratore si utilizza con questo codice:
class Clienti {
nome: string = "Giulia";
cognome: string = "Rossi";
@enumerable(true)
get name() {
return `${this.nome} ${this.cognome}`;
}
}
typescriptDecoratori di TypeScript per parametri
Anche i decoratori di parametri in TypeScript presentano tre parametri: la funzione di costruttore della classe, il nome del metodo e un nome di indice per il parametro. Tuttavia, il parametro stesso non può essere modificato: pertanto questo decoratore può essere utilizzato solo a scopo di verifica. Se, ad esempio, intendi interrogare l’indice, puoi farlo con questo codice:
function print(target: Object, propertyKey: string, parameterIndex: number) {
console.log(`Decorating param ${parameterIndex} from ${propertyKey}`);
}
typescriptSe poi vuoi applicare il decoratore di parametro, il codice è questo:
class Esempio {
testMethod(param0: any, @print param1: any) {}
}
typescriptL’ideale per i siti web statici e per le app: Deploy Now di IONOS mette a tua disposizione un facile staging, una configurazione veloce e flussi di lavoro perfettamente coordinati. Trova il modello giusto per le tue esigenze!