I de­co­ra­to­ri in Ty­pe­Script sono un modo pratico e semplice per assegnare fun­zio­na­li­tà ag­giun­ti­ve agli oggetti senza mo­di­fi­ca­re il codice sorgente. È possibile uti­liz­zar­li su classi, metodi, proprietà, funzioni di accesso e parametri, così da accedere ad an­no­ta­zio­ni e metadati.

Che cosa sono i de­co­ra­to­ri di Ty­pe­Script e a cosa servono?

Il principio dei de­co­ra­to­ri di Ty­pe­Script non è del tutto nuovo. In altri linguaggi di pro­gram­ma­zio­ne sono di­spo­ni­bi­li fun­zio­na­li­tà simili, ad esempio gli attributi in C#, i de­co­ra­to­ri in Python o le an­no­ta­zio­ni in Java. Si tratta di pos­si­bi­li­tà per espandere le fun­zio­na­li­tà di un oggetto senza mo­di­fi­ca­re il codice sorgente. Anche Ty­pe­Script sfrutta questo principio già da tempo. Anche se la maggior parte dei browser non supporta (ancora) i de­co­ra­to­ri di Ty­pe­Script, vale comunque la pena spe­ri­men­ta­re questo approccio e le sue pos­si­bi­li­tà. A partire dalla versione 5.0, l’uso dei de­co­ra­to­ri è stato no­te­vol­men­te sem­pli­fi­ca­to.

I de­co­ra­to­ri di Ty­pe­Script sono uti­liz­za­ti per creare an­no­ta­zio­ni e metadati ag­giun­ti­vi per le classi di Ty­pe­Script e per ag­giun­ge­re elementi. Oltre alle classi è possibile mo­di­fi­ca­re anche metodi, proprietà, metodi di accesso e parametri. Questi ultimi possono essere ve­ri­fi­ca­ti ed è possibile ri­chia­mar­ne i valori. Anche questa è una grande dif­fe­ren­za tra i de­co­ra­to­ri di Ty­pe­Script e il loro equi­va­len­te per Ja­va­Script.

Managed Nextcloud di IONOS Cloud
Lavora con il tuo team sul cloud
  • Massima sicurezza dei tuoi dati
  • Strumenti di col­la­bo­ra­zio­ne per lavorare in team
  • Ag­gior­na­men­ti au­to­ma­ti­ci

Sintassi e fun­zio­na­men­to dei de­co­ra­to­ri

Quando aggiungi i de­co­ra­to­ri di Ty­pe­Script a un oggetto, in realtà stai ri­chia­man­do una funzione che può essere eseguita senza mo­di­fi­ca­re il codice sorgente. Ciò aumenta la fun­zio­na­li­tà e preserva comunque la chiarezza del codice. La sintassi di base si presenta così:

@nomeDecoratore
ty­pe­script

È 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() {
    }
}
ty­pe­script

I singoli com­po­nen­ti dei de­co­ra­to­ri di Ty­pe­Script sono co­sti­tui­ti da questi elementi:

  • target: target indica l’oggetto a cui è stato assegnato il de­co­ra­to­re
  • propertyKey: propertyKey è una stringa con­te­nen­te il nome della classe a cui è stato assegnato un de­co­ra­to­re; tra le varie opzioni, è possibile inserire metodi o proprietà
  • descriptor: in descriptor è possibile inserire ulteriori in­for­ma­zio­ni sull’oggetto a cui si applica il de­co­ra­to­re; le proprietà possibili sono value, writable, enumerable o configurable.

La sintassi dei de­co­ra­to­ri in Ty­pe­Script con due parametri è la seguente:

function FunzioneDecoratore(target: any) {
    console.log(`Decorating ${target.name}`);
}
@FunzioneDecoratore
class MyClass {
}
ty­pe­script

In questo caso, i de­co­ra­to­ri di Ty­pe­Script sono stati applicati a una classe.

I diversi tipi di de­co­ra­to­ri

Esistono diversi tipi di de­co­ra­to­ri di Ty­pe­Script, ciascuno dotato di ca­rat­te­ri­sti­che par­ti­co­la­ri e che de­scri­ve­re­mo in dettaglio più avanti nell’articolo:

  • De­co­ra­to­ri di classe
  • De­co­ra­to­ri di metodo
  • De­co­ra­to­ri di proprietà
  • De­co­ra­to­ri di accessor
  • De­co­ra­to­ri di parametri

De­co­ra­to­ri di Ty­pe­Script per classi

I de­co­ra­to­ri di Ty­pe­Script ti per­met­to­no di per­so­na­liz­za­re le proprietà di una classe e mo­di­fi­car­ne il co­strut­to­re, i metodi o le proprietà. Come primo parametro accettano il co­strut­to­re 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";
ty­pe­script

Nel passaggio suc­ces­si­vo uti­liz­ze­re­mo quindi i de­co­ra­to­ri di Ty­pe­Script per ag­giun­ge­re funzioni sup­ple­men­ta­ri che tuttavia non vanno poi a mo­di­fi­ca­re il codice sorgente. Ag­giun­gia­mo quindi il de­co­ra­to­re @frozen per la classe “Clienti”. Questa funzione fa sì che gli oggetti non possano essere mo­di­fi­ca­ti suc­ces­si­va­men­te. Per alcune proprietà uti­liz­zia­mo @required per dare istru­zio­ni esplicite all’input. Uti­liz­zia­mo inoltre @enumerable per gli elenchi e @deprecated per gli input obsoleti. Per prima cosa ci occupiamo della de­fi­ni­zio­ne dei de­co­ra­to­ri:

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.`);
}
ty­pe­script

Dopo l’utilizzo dei de­co­ra­to­ri di Ty­pe­Script, 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";
ty­pe­script

De­co­ra­to­ri di Ty­pe­Script per metodi

È possibile uti­liz­za­re i de­co­ra­to­ri di Ty­pe­Script anche per i metodi. Fanno eccezione solo i file di di­chia­ra­zio­ne, l’over­loa­ding e la classe “declare”. Nell’esempio seguente uti­liz­zia­mo @enumerable come de­co­ra­to­re 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}`;
    }
}
ty­pe­script

De­co­ra­to­ri di Ty­pe­Script per proprietà

I de­co­ra­to­ri di Ty­pe­Script per le proprietà di una classe (de­co­ra­to­ri di proprietà) possono avere due parametri: la funzione co­strut­to­re della classe e il nome della proprietà. Nell’esempio seguente uti­liz­zia­mo il de­co­ra­to­re per re­sti­tui­re 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";
}
ty­pe­script

De­co­ra­to­ri di Ty­pe­Script per funzioni di accesso

I de­co­ra­to­ri di accessor fun­zio­na­no secondo un principio molto simile ai de­co­ra­to­ri di proprietà. Rispetto a questi ultimi hanno un terzo parametro ag­giun­ti­vo. Nel nostro esempio, questo parametro è il de­scrit­to­re di proprietà per un cliente. A questo punto, se si re­sti­tui­sce un valore uti­liz­zan­do il de­co­ra­to­re di accessor, il valore diventa il nuovo de­scrit­to­re 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;
    }
}
ty­pe­script

Il de­co­ra­to­re si utilizza con questo codice:

class Clienti {
    nome: string = "Giulia";
    cognome: string = "Rossi";
    @enumerable(true)
    get name() {
        return `${this.nome} ${this.cognome}`;
    }
}
ty­pe­script

De­co­ra­to­ri di Ty­pe­Script per parametri

Anche i de­co­ra­to­ri di parametri in Ty­pe­Script pre­sen­ta­no tre parametri: la funzione di co­strut­to­re della classe, il nome del metodo e un nome di indice per il parametro. Tuttavia, il parametro stesso non può essere mo­di­fi­ca­to: pertanto questo de­co­ra­to­re può essere uti­liz­za­to solo a scopo di verifica. Se, ad esempio, intendi in­ter­ro­ga­re l’indice, puoi farlo con questo codice:

function print(target: Object, propertyKey: string, parameterIndex: number) {
    console.log(`Decorating param ${parameterIndex} from ${propertyKey}`);
}
ty­pe­script

Se poi vuoi applicare il de­co­ra­to­re di parametro, il codice è questo:

class Esempio {
    testMethod(param0: any, @print param1: any) {}
}
ty­pe­script
Consiglio

L’ideale per i siti web statici e per le app: Deploy Now di IONOS mette a tua di­spo­si­zio­ne un facile staging, una con­fi­gu­ra­zio­ne veloce e flussi di lavoro per­fet­ta­men­te coor­di­na­ti. Trova il modello giusto per le tue esigenze!

Vai al menu prin­ci­pa­le