Heim > Artikel > Web-Frontend > Dekoratoren in TypeScript verstehen: Ein Ansatz nach den ersten Prinzipien
Dekoratoren in TypeScript bieten einen leistungsstarken Mechanismus zum Ändern des Verhaltens von Klassen, Methoden, Eigenschaften und Parametern. Obwohl sie wie eine moderne Annehmlichkeit erscheinen mögen, basieren Dekoratoren auf dem etablierten Dekoratormuster, das in der objektorientierten Programmierung zu finden ist. Durch die Abstraktion allgemeiner Funktionen wie Protokollierung, Validierung oder Zugriffskontrolle ermöglichen Dekoratoren Entwicklern, saubereren und wartbareren Code zu schreiben.
In diesem Artikel werden wir Dekoratoren von Grund auf untersuchen, ihre Kernfunktionalität aufschlüsseln und sie von Grund auf implementieren. Unterwegs schauen wir uns einige reale Anwendungen an, die den Nutzen von Dekoratoren in der alltäglichen TypeScript-Entwicklung demonstrieren.
In TypeScript ist ein Dekorator einfach eine Funktion, die an eine Klasse, Methode, Eigenschaft oder einen Parameter angehängt werden kann. Diese Funktion wird zur Entwurfszeit ausgeführt und gibt Ihnen die Möglichkeit, das Verhalten oder die Struktur des Codes vor seiner Ausführung zu ändern. Dekoratoren ermöglichen Metaprogrammierung, sodass wir zusätzliche Funktionen hinzufügen können, ohne die ursprüngliche Logik zu ändern.
Beginnen wir mit einem einfachen Beispiel eines Methodendekorators, der protokolliert, wenn eine Methode aufgerufen wird:
function log(target: any, propertyKey: string, descriptor: PropertyDescriptor) { const originalMethod = descriptor.value; descriptor.value = function (...args: any[]) { console.log(`Calling ${propertyKey} with arguments: ${args}`); return originalMethod.apply(this, args); }; return descriptor; } class Example { @log greet(name: string) { return `Hello, ${name}`; } } const example = new Example(); example.greet('John');
Hier umschließt der Log-Dekorator die Greet-Methode und protokolliert ihren Aufruf und ihre Parameter, bevor er sie ausführt. Dieses Muster ist nützlich, um übergreifende Themen wie die Protokollierung von der Kernlogik zu trennen.
Dekoratoren in TypeScript sind Funktionen, die Metadaten zu dem Element, das sie dekorieren, aufnehmen. Basierend auf diesen Metadaten (wie Klassenprototypen, Methodennamen oder Eigenschaftsdeskriptoren) können Dekorateure das Verhalten ändern oder sogar das dekorierte Objekt ersetzen.
Dekoratoren können auf verschiedene Ziele mit jeweils unterschiedlichen Zwecken angewendet werden:
function classDecorator(constructor: Function) { // Modify or extend the class constructor or prototype }
function methodDecorator(target: any, propertyKey: string, descriptor: PropertyDescriptor) { // Modify the method's descriptor }
function propertyDecorator(target: any, propertyKey: string) { // Modify the behavior of the property }
function parameterDecorator(target: any, propertyKey: string, parameterIndex: number) { // Modify or inspect the method's parameter }
Eine der mächtigsten Eigenschaften von Dekorateuren ist ihre Fähigkeit, Argumente anzunehmen, sodass Sie ihr Verhalten anpassen können. Erstellen wir beispielsweise einen Methodendekorator, der Methodenaufrufe bedingt auf der Grundlage eines Arguments protokolliert.
function logConditionally(shouldLog: boolean) { return function (target: any, propertyKey: string, descriptor: PropertyDescriptor) { const originalMethod = descriptor.value; descriptor.value = function (...args: any[]) { if (shouldLog) { console.log(`Calling ${propertyKey} with arguments: ${args}`); } return originalMethod.apply(this, args); }; return descriptor; }; } class Example { @logConditionally(true) greet(name: string) { return `Hello, ${name}`; } } const example = new Example(); example.greet('TypeScript Developer');
Durch die Übergabe von true an den logConditionally-Dekorator stellen wir sicher, dass die Methode ihre Ausführung protokolliert. Wenn wir false übergeben, wird die Protokollierung übersprungen. Diese Flexibilität ist der Schlüssel dazu, Dekorateure vielseitig und wiederverwendbar zu machen.
Dekoratoren haben in vielen Bibliotheken und Frameworks praktische Anwendung gefunden. Hier sind einige bemerkenswerte Beispiele, die veranschaulichen, wie Dekorateure komplexe Funktionen optimieren:
import { IsEmail, IsNotEmpty } from 'class-validator'; class User { @IsNotEmpty() name: string; @IsEmail() email: string; }
In diesem Beispiel stellen die Dekoratoren @IsEmail und @IsNotEmpty sicher, dass das E-Mail-Feld eine gültige E-Mail-Adresse ist und das Namensfeld nicht leer ist. Diese Dekoratoren sparen Zeit, da keine manuelle Validierungslogik erforderlich ist.
import { Entity, Column, PrimaryGeneratedColumn } from 'typeorm'; @Entity() class User { @PrimaryGeneratedColumn() id: number; @Column() name: string; @Column() email: string; }
Hier definieren @Entity, @Column und @PrimaryGeneratedColumn die Struktur der Benutzertabelle. Diese Dekoratoren abstrahieren die Komplexität der SQL-Tabellenerstellung und machen den Code dadurch lesbarer und wartbarer.
@Injectable({ providedIn: 'root', }) class UserService { constructor(private http: HttpClient) {} }
Der @Injectable-Dekorator signalisiert in diesem Fall dem Abhängigkeitsinjektionssystem von Angular, dass der UserService global bereitgestellt werden soll. Dies ermöglicht eine nahtlose Integration von Diensten in der gesamten Anwendung.
Dekorateure sind im Kern nur Funktionen. Lassen Sie uns den Prozess der Erstellung von Dekorateuren von Grund auf aufschlüsseln:
A class decorator receives the constructor of the class and can be used to modify the class prototype or even replace the constructor.
function AddTimestamp(constructor: Function) { constructor.prototype.timestamp = new Date(); } @AddTimestamp class MyClass { id: number; constructor(id: number) { this.id = id; } } const instance = new MyClass(1); console.log(instance.timestamp); // Outputs the current timestamp
A method decorator modifies the method descriptor, allowing you to alter the behavior of the method itself.
function logExecutionTime(target: any, propertyKey: string, descriptor: PropertyDescriptor) { const originalMethod = descriptor.value; descriptor.value = function (...args: any[]) { const start = performance.now(); const result = originalMethod.apply(this, args); const end = performance.now(); console.log(`${propertyKey} executed in ${end - start}ms`); return result; }; return descriptor; } class Service { @logExecutionTime execute() { // Simulate work for (let i = 0; i < 1e6; i++) {} } } const service = new Service(); service.execute(); // Logs the execution time
A property decorator allows you to intercept property access and modification, which can be useful for tracking changes.
function trackChanges(target: any, propertyKey: string) { let value = target[propertyKey]; const getter = () => value; const setter = (newValue: any) => { console.log(`${propertyKey} changed from ${value} to ${newValue}`); value = newValue; }; Object.defineProperty(target, propertyKey, { get: getter, set: setter, }); } class Product { @trackChanges price: number; constructor(price: number) { this.price = price; } } const product = new Product(100); product.price = 200; // Logs the change
Decorators in TypeScript allow you to abstract and reuse functionality in a clean, declarative manner. Whether you're working with validation, ORMs, or dependency injection, decorators help reduce boilerplate and keep your code modular and maintainable. Understanding how they work from first principles makes it easier to leverage their full potential and craft custom solutions tailored to your application.
By taking a deeper look at the structure and real-world applications of decorators, you've now seen how they can simplify complex coding tasks and streamline code across various domains.
Das obige ist der detaillierte Inhalt vonDekoratoren in TypeScript verstehen: Ein Ansatz nach den ersten Prinzipien. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!