Les Ty­peS­cript De­co­ra­tors (dé­co­ra­teurs Ty­peS­cript) per­met­tent d’ajouter des fonctions sup­plé­men­taires à des objets, et ce sans devoir modifier le code source. Ils peuvent être appliqués aux classes, aux méthodes, aux pro­prié­tés, aux fonctions d’accès et aux pa­ra­mètres, et accèdent aux an­no­ta­tions et mé­ta­don­nées.

Les Ty­peS­cript De­co­ra­tors : c’est quoi et à quoi ça sert ?

Le principe des Ty­peS­cript De­co­ra­tors n’a fon­da­men­ta­le­ment rien de nouveau. On trouve des concepts si­mi­laires dans d’autres langages de pro­gram­ma­tion comme les attributs en C#, les dé­co­ra­teurs en Python ou les an­no­ta­tions en Java. Il s’agit de pouvoir étendre les fonctions d’un objet sans en modifier le code source. Ty­peS­cript aussi travaille depuis longtemps selon cette approche. Certes, la plupart des na­vi­ga­teurs ne sup­por­tent pas (encore) les Ty­peS­cript De­co­ra­tors, mais il est tout de même in­té­res­sant d’essayer cette méthode et ses pos­si­bi­li­tés. Depuis la version Ty­peS­cript 5.0, leur uti­li­sa­tion a été con­si­dé­ra­ble­ment sim­pli­fiée.

Les Ty­peS­cript De­co­ra­tors sont utilisés pour ajouter des an­no­ta­tions et des mé­ta­don­nées sup­plé­men­taires aux classes Ty­peS­cript et aux éléments. Outre les classes, il est possible de modifier les méthodes, les pro­prié­tés, les méthodes d’accès ainsi que les pa­ra­mètres. Ces derniers peuvent être contrôlés et leurs valeurs con­sul­tées. Il s’agit de l’une des grandes dif­fé­rences entre les Ty­peS­cript De­co­ra­tors et leur équi­valent pour Ja­vaS­cript.

Syntaxe et fonc­tion­ne­ment des dé­co­ra­teurs

En ajoutant des Ty­peS­cript De­co­ra­tors à un objet, vous appelez une fonction qui peut être exécutée sans mo­di­fi­ca­tion du code source. Vous augmentez ainsi la fonc­tion­na­lité tout en gardant un code clair. La syntaxe de base est la suivante :

@nomDuDecorateur
ty­pes­cript

Vous pouvez créer cette fonction avec deux ou trois pa­ra­mètres. La syntaxe de la fonction à trois pa­ra­mètres prend la forme suivante :

function decoratorFonction(target: any, propertyKey: string, descriptor: PropertyDescriptor) {
    console.log(`Decorating ${propertyKey} of class ${target.constructor.name}`);
}
class MyClass {
    @decoratorFonction
    myMethod() {
    }
}
ty­pes­cript

Les dif­fé­rents éléments des Ty­peS­cript De­co­ra­tors sont les suivants :

  • target : désigne l’objet auquel le dé­co­ra­teur a été attribué
  • propertyKey : est un string contenant le nom de la classe à laquelle un dé­co­ra­teur a été attribué ; il peut s’agir, entre autres, de méthodes ou de pro­prié­tés
  • descriptor : permet de stocker des in­for­ma­tions sup­plé­men­taires sur l’objet sur lequel le dé­co­ra­teur est appliqué ; les pro­prié­tés possibles sont value, writable, enumerable ou configurable.

Voici, ci-dessous, la syntaxe des Ty­peS­cript De­co­ra­tors a deux pa­ra­mètres :

function decoratorFonction(target: any) {
    console.log(`Decorating ${target.name}`);
}
@decoratorFonction
class MyClass {
}
ty­pes­cript

Dans ce cas, les Ty­peS­cript De­co­ra­tors ont été appliqués à une classe.

Les dif­fé­rents types de dé­co­ra­teurs

Il existe dif­fé­rents types de Ty­peS­cript De­co­ra­tors. Nous les pré­sen­tons plus en détail ci-après, avec leurs par­ti­cu­la­ri­tés res­pec­tives :

  • Class De­co­ra­tors
  • Method De­co­ra­tors
  • Property De­co­ra­tors
  • Accessor De­co­ra­tors
  • Parameter De­co­ra­tors

Ty­peS­cript De­co­ra­tors pour les classes

Les Ty­peS­cript De­co­ra­tors per­met­tent d’adapter les ca­rac­té­ris­tiques d’une classe et de modifier son cons­truc­teur, ses méthodes ou ses pro­prié­tés. Dès que vous « décorez » la classe avec une fonction, vous recevez le cons­truc­teur comme premier paramètre. Voici un exemple de code traitant d’une liste de clients. Elle a quelques pro­prié­tés privées et publiques :

class Client {
    private static userType: string = "Generic";
    private _email: string;
    public nomduclient: string;
    public rue: string = "";
    public lieuderesidence: string = "";
    public pays: string = "";
    constructor(nomduclient: string, email: string) {
        this.nomduclient = nomduclient;
        this._email = email;
    }
    static get userType() {
        return Client.userType;
    }
    get email() {
        return this._email;
    }
    set email(nouvelemail: string) {
        this._email = nouvelemail;
    }
    adresse(): string {
        return `${this.rue}\n${this.lieuderesidence}\n${this.pays}`;
    }
}
const p = new Client("clientexemple", "name@exemple.com");
p.rue = "6 rue de Drulingen";
p.lieuderesidence = "Strasbourg";
ty­pes­cript

Dans l’étape suivante, nous utilisons les Ty­peS­cript De­co­ra­tors pour ajouter d’autres fonctions qui ne modifient toutefois pas le code source après coup. Nous ajoutons ainsi le dé­co­ra­teur @frozen pour la classe « Client ». Cette fonction fait en sorte que les objets ne puissent pas être modifiés ul­té­rieu­re­ment. Pour certaines pro­prié­tés, nous utilisons @required pour indiquer ex­pli­ci­te­ment la saisie. Nous utilisons aussi @enumerable pour les énu­mé­ra­tions et @deprecated pour les entrées obsolètes. Voyons tout d’abord ensemble la dé­fi­ni­tion des dé­co­ra­teurs :

function frozen(constructor: Function) {
    Object.freeze(constructor);
    Object.freeze(constructor.prototype);
}
function required(target: any, propertyKey: string) {
}
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­pes­cript

Après l’uti­li­sa­tion des Ty­peS­cript De­co­ra­tors, le code résultant a la syntaxe suivante :

@frozen
class Client {
    private static userType: string = "Generic";
    @required
    private _email: string;
    @required
    public nomduclient: string;
    public rue: string = "";
    public lieuderesidence: string = "";
    public pays: string = "";
    constructor(nomduclient: string, email: string) {
        this. nomduclient = nomduclient;
        this._email = email;
    }
    @enumerable(false)
    static get userType() {
        return Client.userType;
    }
    get email() {
        return this._email;
    }
    set email(nouvelemail: string) {
        this._email = nouvelemail;
    }
    @deprecated
    adresse(): string {
        return `${this.rue}\n${this.lieuderesidence}\n${this.pays}`;
    }
}
const p = new Client("clientexemple", "nom@exemple.com");
p.rue = "6 rue de Drulingen";
p.lieuderesidence = "Strasbourg";
ty­pes­cript

Ty­peS­cript De­co­ra­tors pour les méthodes

L’uti­li­sa­tion de Ty­peS­cript De­co­ra­tors est également possible pour les méthodes, exception faite des fichiers de dé­cla­ra­tion, de l’over­loa­ding (surcharge de fonction) ou de la classe « Declare ». Dans l’exemple suivant, nous utilisons @enumerable comme dé­co­ra­teur pour la méthode getName dans la classe « Personne » :

const enumerable = (value: boolean) => {
    return (target: any, propertyKey: string, propertyDescriptor: PropertyDescriptor) => {
        propertyDescriptor.enumerable = value;
    }
}
class Personne {
    prenom: string = "Julie"
    nom: string = "Rault"
    @enumerable(true)
    getName () {
        return `${this.prenom} ${this.nom}`;
    }
}
ty­pes­cript

Ty­peS­cript De­co­ra­tors pour les pro­prié­tés

Les Ty­peS­cript De­co­ra­tors pour les pro­prié­tés d’une classe (Property De­co­ra­tors) ont deux pa­ra­mètres : la fonction de cons­truc­teur de la classe et le nom de la propriété. Dans l’exemple suivant, nous utilisons le dé­co­ra­teur pour afficher le nom d’une propriété (ici le nom du client) :

const printPropertyName = (target: any, propertyName: string) => {
    console.log(propertyName);
};
class Client {
    @printPropertyName
    name: string = "Julie";
}
ty­pes­cript

Ty­peS­cript De­co­ra­tors pour les fonctions d’accès

Les Accessor De­co­ra­tors fonc­tion­nent selon un principe très similaire à celui des Property De­co­ra­tors. À la dif­fé­rence de ces derniers, ils ont un troisième paramètre en plus. Dans notre exemple, il s’agit du Property Des­crip­tor pour un client. En indiquant une valeur avec l’Accessor Decorator, celui-ci devient le nouveau Property Des­crip­tor. Dans le code suivant, la valeur booléenne (« True » ou « False ») de enumerable est ainsi modifiée.

const enumerable = (value: boolean) => {
    return (target: any, propertyKey: string, descriptor: PropertyDescriptor) => {
        descriptor.enumerable = value;
    }
}
ty­pes­cript

Voici comment appliquer le dé­co­ra­teur :

class Client {
    prenom: string = "Julie";
    nom: string = "Rault";
    @enumerable(true)
    get name() {
        return `${this.prenom} ${this.nom}`;
    }
}
ty­pes­cript

Ty­peS­cript De­co­ra­tors pour les pa­ra­mètres

Les Ty­peS­cript De­co­ra­tors de type Parameter Decorator disposent également de trois pa­ra­mètres : la fonction de cons­truc­teur de classe, le nom de la méthode et en plus une dé­sig­na­tion d’index du paramètre. Toutefois, le paramètre en soi ne peut pas être modifié, de sorte que ce dé­co­ra­teur peut être utilisé uni­que­ment pour la vé­ri­fi­ca­tion. Si vous souhaitez, par exemple, consulter l’index, faites-le avec ce code :

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

Si vous appliquez ensuite le paramètre Dé­co­ra­teur, le code est le suivant :

class Exemple {
    testMethod(param0: any, @print param1: any) {}
}
ty­pes­cript
Conseil

Idéal pour les sites Internet statiques et les ap­pli­ca­tions : avec Deploy Now de IONOS, vous bé­né­fi­ciez d’un en­vi­ron­ne­ment de si­mu­la­tion (staging) simple, d’une ins­tal­la­tion rapide et de workflows par­fai­te­ment har­mo­ni­sés. Trouvez le modèle le mieux adapté à vos besoins !

Aller au menu principal