TypeScript Decorators: Klassen, Methoden und Eigenschaften
TypeScript Decorators sind eine praktische und einfache Methode, um Objekten zusätzliche Funktionen zuzuweisen, ohne dabei den Quellcode zu verändern. Sie können auf Klassen, Methoden, Eigenschaften, Zugriffsfunktionen und Parameter angewendet werden und greifen auf Annotationen und Metadaten zu.
Was sind TypeScript Decorators und wofür werden sie genutzt?
Das Prinzip der TypeScript Decorators ist grundsätzlich nicht neu. In anderen Programmiersprachen finden sich ähnliche Features wie zum Beispiel Attribute in C#, Decorators in Python oder Annotationen in Java. Es handelt sich dabei um eine Möglichkeit, die Funktionalität eines Objekts zu erweitern, ohne dabei den Quellcode zu verändern. Auch TypeScript arbeitet bereits seit längerer Zeit mit diesem Ansatz. Zwar unterstützen die meisten Browser TypeScript Decorators (noch) nicht, es lohnt sich aber trotzdem, diese Herangehensweise und ihre Möglichkeiten auszuprobieren. Seit Version 5.0 wurde der Einsatz der Dekoratoren noch einmal massiv vereinfacht.
TypeScript Decorators werden genutzt, um Anmerkungen (Annotations) und zusätzliche Metadaten für TypeScript Classes und Elemente hinzuzufügen. Dabei lassen sich neben den Klassen auch Methoden, Eigenschaften, Zugriffsmethoden und Parameter verändern. Letztere können dabei überprüft werden und ihre Werte lassen sich abrufen. Das ist auch ein großer Unterschied zwischen TypeScript Decorators und ihrem Äquivalent für JavaScript.
- Vollständige Datensouveränität in deutschen Rechenzentren
- Managed Service ohne Administrationsaufwand
- File-Sharing, Dokumentenbearbeitung & Kommunikation
Syntax und Funktionsweise der Dekoratoren
Fügen Sie TypeScript Decorators zu einem Objekt hinzu, rufen Sie damit strenggenommen eine Funktion auf, die ohne eine Änderung des Quellcodes ausgeführt werden kann. Sie erhöhen somit die Funktionalität und halten den Code trotzdem übersichtlich. Die grundsätzliche Syntax sieht wie folgt aus:
@nameDesDekorators
typescriptDiese Funktion erstellen Sie entweder mit zwei oder drei Parametern. Die Syntax für die Funktion mit drei Parametern sieht so aus:
function decoratorFunktion(target: any, propertyKey: string, descriptor: PropertyDescriptor) {
console.log(`Decorating ${propertyKey} of class ${target.constructor.name}`);
}
class MyClass {
@decoratorFunktion
myMethod() {
}
}
typescriptDie einzelnen Bestandteile der TypeScript Decorators setzen sich wie folgtzusammen:
-
target
:target
bezeichnet das Objekt, dem der Dekorator zugewiesen wurde -
propertyKey
:propertyKey
ist ein String, der den Namen der Klasse enthält, der ein Dekorator zugewiesen wurde; möglich sind unter anderem Methoden oder Eigenschaften -
descriptor
: Unterdescriptor
werden weitere Informationen über das Objekt hinterlegt, auf das der Dekorator angewendet wird; mögliche Eigenschaften sindvalue
,writable
,enumerable
oderconfigurable
.
Die Syntax von TypeScript Decorators mit zwei Parametern sehen Sie hier:
function decoratorFunktion(target: any) {
console.log(`Decorating ${target.name}`);
}
@decoratorFunktion
class MyClass {
}
typescriptIn diesem Fall wurde TypeScript Decorators auf eine Klasse angewandt.
Die unterschiedlichen Typen von Dekoratoren
Es gibt verschiedene Arten von TypeScript Decorators, die wir Ihnen im weiteren Verlauf genauer vorstellen und die alle Besonderheiten aufweisen:
- Class Decorators
- Method Decorators
- Property Decorators
- Accessor Decorators
- Parameter Decorators
TypeScript Decorators für Klassen
Möchten Sie die Eigenheiten einer Klasse anpassen und ihren Konstruktor, ihre Methoden oder Eigenschaften ändern, ist dies mit TypeScript Decorators möglich. Sie erhalten dabei als ersten Parameter den Konstruktor, sobald Sie die Klasse mit einer Funktion „dekorieren“. Dies ist ein beispielhafter Code, bei dem wir mit einer Kundenliste arbeiten. Sie hat einige private und einige öffentliche Eigenschaften:
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";
typescriptIm nächsten Schritt nutzen wir nun TypeScript Decorators, um weitere Funktionen hinzuzufügen, die den Quellcode allerdings nicht nachträglich 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 nachträglich verändern lassen. Für einige Eigenschaften nutzen wir @required
, um die Eingabe ausdrücklich anzuweisen. Des Weiteren verwenden wir @enumerable
für Auflistungen und @deprecated
für veraltete Eingaben. Zunächst kümmern wir uns um die Definition der Dekoratoren:
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.`);
}
typescriptNach dem Einsatz von TypeScript Decorators sieht der abschließende 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";
typescriptTypeScript Decorators für Methoden
Auch für Methoden ist der Einsatz von TypeScript Decorators möglich. Ausnahmen sind Declaration Files, das Overloading 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}`;
}
}
typescriptTypeScript Decorators für Propertys
TypeScript Decorators für die Eigenschaften einer Klasse (Property Decorators) haben zwei Parameter: die Konstruktor-Funktion der Klasse und den Namen der Eigenschaft. Im folgenden Beispiel nutzen wir den Dekorator, um den Namen einer Eigenschaft (hier der Kundenname) auszugeben:
const printPropertyName = (target: any, propertyName: string) => {
console.log(propertyName);
};
class Kunden {
@printPropertyName
name: string = "Julia";
}
typescriptTypeScript Decorators für Zugriffsfunktionen
Accessor Decorators funktionieren nach einem ganz ähnlichen Prinzip wie Property Decorators. Im Vergleich zu diesen haben sie einen zusätzlichen dritten Parameter. In unserem Beispiel handelt es sich dabei um den Property Descriptor für einen Kunden oder eine Kundin. Geben Sie nun mit dem Accessor Decorator einen Wert aus, wird dieser zum neuen Property Descriptor. Im folgenden Code wird so der boolesche Wert („true“ oder „false“) von enumerable
geändert. Dies ist unser Ausgangspunkt:
const enumerable = (value: boolean) => {
return (target: any, propertyKey: string, descriptor: PropertyDescriptor) => {
descriptor.enumerable = value;
}
}
typescriptSo setzen Sie den Dekorator ein:
class Kunden {
vorname: string = "Julia";
nachname: string = "Schulz";
@enumerable(true)
get name() {
return `${this.vorname} ${this.nachname}`;
}
}
typescriptTypeScript Decorators für Parameter
TypeScript Decorators vom Typ Parameter Decorator verfügen ebenfalls über drei Parameter: die Konstruktor-Funktion der Klasse, den Namen der Methode und zusätzlich eine Indexbezeichnung des Parameters. Der Parameter selbst kann allerdings nicht geändert werden, sodass dieser Dekorator nur zur Überprüfung verwendet werden kann. Möchten Sie zum Beispiel den Index erfragen, funktioniert das mit diesem Code:
function print(target: Object, propertyKey: string, parameterIndex: number) {
console.log(`Decorating param ${parameterIndex} from ${propertyKey}`);
}
typescriptWenden Sie dann den Parameter Decorator an, ist dies der Code:
class Beispiel {
testMethod(param0: any, @print param1: any) {}
}
typescriptIdeal für statische Websites und Apps gleichermaßen: Mit Deploy Now von IONOS profitieren Sie von einfachem Staging, einem schnellen Setup und perfekt abgestimmten Workflows. Finden Sie das passende Modell für Ihre Zwecke!