Ty­pe­Script De­co­ra­tors sind eine prak­ti­sche und einfache Methode, um Objekten zu­sätz­li­che Funk­tio­nen zu­zu­wei­sen, ohne dabei den Quellcode zu verändern. Sie können auf Klassen, Methoden, Ei­gen­schaf­ten, Zu­griffs­funk­tio­nen und Parameter an­ge­wen­det werden und greifen auf An­no­ta­tio­nen und Metadaten zu.

Was sind Ty­pe­Script De­co­ra­tors und wofür werden sie genutzt?

Das Prinzip der Ty­pe­Script De­co­ra­tors ist grund­sätz­lich nicht neu. In anderen Pro­gram­mier­spra­chen finden sich ähnliche Features wie zum Beispiel Attribute in C#, De­co­ra­tors in Python oder An­no­ta­tio­nen in Java. Es handelt sich dabei um eine Mög­lich­keit, die Funk­tio­na­li­tät eines Objekts zu erweitern, ohne dabei den Quellcode zu verändern. Auch Ty­pe­Script arbeitet bereits seit längerer Zeit mit diesem Ansatz. Zwar un­ter­stüt­zen die meisten Browser Ty­pe­Script De­co­ra­tors (noch) nicht, es lohnt sich aber trotzdem, diese Her­an­ge­hens­wei­se und ihre Mög­lich­kei­ten aus­zu­pro­bie­ren. Seit Version 5.0 wurde der Einsatz der De­ko­ra­to­ren noch einmal massiv ver­ein­facht.

Ty­pe­Script De­co­ra­tors werden genutzt, um An­mer­kun­gen (An­no­ta­ti­ons) und zu­sätz­li­che Metadaten für Ty­pe­Script Classes und Elemente hin­zu­zu­fü­gen. Dabei lassen sich neben den Klassen auch Methoden, Ei­gen­schaf­ten, Zu­griffs­me­tho­den und Parameter verändern. Letztere können dabei überprüft werden und ihre Werte lassen sich abrufen. Das ist auch ein großer Un­ter­schied zwischen Ty­pe­Script De­co­ra­tors und ihrem Äqui­va­lent für Ja­va­Script.

Managed Nextcloud by IONOS Cloud
Team­ar­beit in der eigenen Cloud
  • Voll­stän­di­ge Da­ten­sou­ve­rä­ni­tät in deutschen Re­chen­zen­tren
  • Managed Service ohne Ad­mi­nis­tra­ti­ons­auf­wand
  • File-Sharing, Do­ku­men­ten­be­ar­bei­tung & Kom­mu­ni­ka­ti­on

Syntax und Funk­ti­ons­wei­se der De­ko­ra­to­ren

Fügen Sie Ty­pe­Script De­co­ra­tors zu einem Objekt hinzu, rufen Sie damit streng­ge­nom­men eine Funktion auf, die ohne eine Änderung des Quell­codes aus­ge­führt werden kann. Sie erhöhen somit die Funk­tio­na­li­tät und halten den Code trotzdem über­sicht­lich. Die grund­sätz­li­che Syntax sieht wie folgt aus:

@nameDesDekorators
ty­pe­script

Diese Funktion erstellen Sie entweder mit zwei oder drei Pa­ra­me­tern. Die Syntax für die Funktion mit drei Pa­ra­me­tern sieht so aus:

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

Die einzelnen Be­stand­tei­le der Ty­pe­Script De­co­ra­tors setzen sich wie folgt­zu­sam­men:

  • target: target be­zeich­net das Objekt, dem der Dekorator zu­ge­wie­sen wurde
  • propertyKey: propertyKey ist ein String, der den Namen der Klasse enthält, der ein Dekorator zu­ge­wie­sen wurde; möglich sind unter anderem Methoden oder Ei­gen­schaf­ten
  • descriptor: Unter descriptor werden weitere In­for­ma­tio­nen über das Objekt hin­ter­legt, auf das der Dekorator an­ge­wen­det wird; mögliche Ei­gen­schaf­ten sind value, writable, enumerable oder configurable.

Die Syntax von Ty­pe­Script De­co­ra­tors mit zwei Pa­ra­me­tern sehen Sie hier:

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

In diesem Fall wurde Ty­pe­Script De­co­ra­tors auf eine Klasse angewandt.

Die un­ter­schied­li­chen Typen von De­ko­ra­to­ren

Es gibt ver­schie­de­ne Arten von Ty­pe­Script De­co­ra­tors, die wir Ihnen im weiteren Verlauf genauer vor­stel­len und die alle Be­son­der­hei­ten aufweisen:

  • 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­pe­Script De­co­ra­tors für Klassen

Möchten Sie die Ei­gen­hei­ten einer Klasse anpassen und ihren Kon­struk­tor, ihre Methoden oder Ei­gen­schaf­ten ändern, ist dies mit Ty­pe­Script De­co­ra­tors möglich. Sie erhalten dabei als ersten Parameter den Kon­struk­tor, sobald Sie die Klasse mit einer Funktion „de­ko­rie­ren“. Dies ist ein bei­spiel­haf­ter Code, bei dem wir mit einer Kun­den­lis­te arbeiten. Sie hat einige private und einige öf­fent­li­che Ei­gen­schaf­ten:

class Kunden {
    private static userType: string = "Generic";
    private _email: string;
    public kundenname: string;
    public strasse: string = "";
    public wohnort: string = "";
    public land: string = "";
    constructor(kundenname: string, email: string) {
        this.kundenname = kundenname;
        this._email = email;
    }
    Static get userType() {
        return Kunden.userType;
    }
    get email() {
        return this._email;
    }
    set email(neueEmail: string) {
        this._email = neueEmail;
    }
    adresse(): string {
        return `${this.strasse}\n${this.wohnort}\n${this.land}`;
    }
}
const p = new Kunden("beispielKunde", "name@beispiel.com");
p.strasse = "Hofgasse 2";
p.wohnort = "Berlin";
ty­pe­script

Im nächsten Schritt nutzen wir nun Ty­pe­Script De­co­ra­tors, um weitere Funk­tio­nen hin­zu­zu­fü­gen, die den Quellcode al­ler­dings nicht nach­träg­lich verändern. So fügen wir für die Klasse „Kunden“ den Dekorator @frozen hinzu. Diese Funktion sorgt dafür, dass die Objekte sich nicht nach­träg­lich verändern lassen. Für einige Ei­gen­schaf­ten nutzen wir @required, um die Eingabe aus­drück­lich an­zu­wei­sen. Des Weiteren verwenden wir @enumerable für Auf­lis­tun­gen und @deprecated für veraltete Eingaben. Zunächst kümmern wir uns um die De­fi­ni­ti­on der De­ko­ra­to­ren:

function frozen(constructor: Function) {
    Object.freeze(constructor);
    Object.freeze(constructor.prototype);
}
function required(target: any, propertyKey: string) {
    // Logik für Required-Decorator
}
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

Nach dem Einsatz von Ty­pe­Script De­co­ra­tors sieht der ab­schlie­ßen­de Code dann wie folgt aus:

@frozen
class Kunden {
    private static userType: string = "Generic";
    @required
    private _email: string;
    @required
    public kundenname: string;
    public strasse: string = "";
    public wohnort: string = "";
    public land: string = "";
    constructor(kundenname: string, email: string) {
        this.kundenname = kundenname;
        this._email = email;
    }
    @enumerable(false)
    get userType() {
        return Kunden.userType;
    }
    get email() {
        return this._email;
    }
    set email(neueEmail: string) {
        this._email = neueEmail;
    }
    @deprecated
    addresse(): string {
        return `${this.strasse}\n${this.wohnort}\n${this.land}`;
    }
}
const p = new Kunden("beispielKunde", "name@beispiel.com");
p.strasse = "Hofgasse, 2";
p.wohnort = "Berlin";
ty­pe­script

Ty­pe­Script De­co­ra­tors für Methoden

Auch für Methoden ist der Einsatz von Ty­pe­Script De­co­ra­tors möglich. Ausnahmen sind De­cla­ra­ti­on Files, das Over­loa­ding oder die Klasse „declare“. Im folgenden Beispiel nutzen wir @enumerable als Dekorator für die Methode getName in der Klasse „Person“:

const enumerable = (value: boolean) => {
    return (target: any, propertyKey: string, propertyDescriptor: PropertyDescriptor) => {
        propertyDescriptor.enumerable = value;
    }
}
class Person {
    vorname: string = "Julia"
    nachname: string = "Schulz"
    @enumerable(true)
    getName () {
        return `${this.vorname} ${this.nachname}`;
    }
}
ty­pe­script

Ty­pe­Script De­co­ra­tors für Propertys

Ty­pe­Script De­co­ra­tors für die Ei­gen­schaf­ten einer Klasse (Property De­co­ra­tors) haben zwei Parameter: die Kon­struk­tor-Funktion der Klasse und den Namen der Ei­gen­schaft. Im folgenden Beispiel nutzen wir den Dekorator, um den Namen einer Ei­gen­schaft (hier der Kun­den­na­me) aus­zu­ge­ben:

const printPropertyName = (target: any, propertyName: string) => {
    console.log(propertyName);
};
class Kunden {
    @printPropertyName
    name: string = "Julia";
}
ty­pe­script

Ty­pe­Script De­co­ra­tors für Zu­griffs­funk­tio­nen

Accessor De­co­ra­tors funk­tio­nie­ren nach einem ganz ähnlichen Prinzip wie Property De­co­ra­tors. Im Vergleich zu diesen haben sie einen zu­sätz­li­chen dritten Parameter. In unserem Beispiel handelt es sich dabei um den Property De­scrip­tor für einen Kunden oder eine Kundin. Geben Sie nun mit dem Accessor Decorator einen Wert aus, wird dieser zum neuen Property De­scrip­tor. Im folgenden Code wird so der boolesche Wert („true“ oder „false“) von enumerable geändert. Dies ist unser Aus­gangs­punkt:

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

So setzen Sie den Dekorator ein:

class Kunden {
    vorname: string = "Julia";
    nachname: string = "Schulz";
    @enumerable(true)
    get name() {
        return `${this.vorname} ${this.nachname}`;
    }
}
ty­pe­script

Ty­pe­Script De­co­ra­tors für Parameter

Ty­pe­Script De­co­ra­tors vom Typ Parameter Decorator verfügen ebenfalls über drei Parameter: die Kon­struk­tor-Funktion der Klasse, den Namen der Methode und zu­sätz­lich eine In­dex­be­zeich­nung des Pa­ra­me­ters. Der Parameter selbst kann al­ler­dings nicht geändert werden, sodass dieser Dekorator nur zur Über­prü­fung verwendet werden kann. Möchten Sie zum Beispiel den Index erfragen, funk­tio­niert das mit diesem Code:

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

Wenden Sie dann den Parameter Decorator an, ist dies der Code:

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

Ideal für statische Websites und Apps glei­cher­ma­ßen: Mit Deploy Now von IONOS pro­fi­tie­ren Sie von einfachem Staging, einem schnellen Setup und perfekt ab­ge­stimm­ten Workflows. Finden Sie das passende Modell für Ihre Zwecke!

Zum Hauptmenü