Tìm Hiểu Về Decorator Trong TypeScript
Trong bài viết này, chúng ta sẽ cùng khám phá về Decorator trong TypeScript, một tính năng mạnh mẽ giúp mở rộng và thay đổi hành vi của các class, method, property và parameter. Việc sử dụng Decorator không chỉ làm cho code trở nên dễ đọc mà còn giúp bảo trì dễ dàng hơn trong quá trình phát triển ứng dụng.
1. Decorator Là Gì?
Decorator là một function đặc biệt được sử dụng để thay đổi hoặc mở rộng hành vi của class, method, property hoặc parameter trong TypeScript. Điều này cho phép chúng ta thêm chức năng mới mà không cần phải sửa đổi code ban đầu của đối tượng.
2. Mối Quan Hệ Giữa Decorator và Lập Trình Hướng Khía Cạnh (AOP)
Decorator trong TypeScript có mối liên hệ đặc biệt với Lập Trình Hướng Khía Cạnh (Aspect-Oriented Programming - AOP). AOP là một mô hình nhằm mục đích tách biệt các mối quan tâm xuyên suốt khỏi logic chính của ứng dụng, như logging, bảo mật, và xử lý ngoại lệ.
- Aspect: Module chứa logic phụ trợ.
- Join Point: Điểm trong quá trình thực thi nơi một aspect có thể được áp dụng.
- Advice: Đoạn code thực thi tại một join point.
- Pointcut: Biểu thức định nghĩa join points mà một aspect sẽ áp dụng.
Decorator trong TypeScript là một biểu hiện cụ thể của các khái niệm này.
3. Decorator và Decorator Design Pattern
Decorator Design Pattern cũng liên quan đến việc thay đổi hoặc mở rộng hành vi của đối tượng. Đây là một design pattern cho phép thêm chức năng cho các đối tượng mà không ảnh hưởng đến các đối tượng khác cùng class. Design pattern này thường được triển khai thông qua composition.
Ví Dụ Về Decorator Design Pattern
typescript
interface Component {
operation(): string;
}
class ConcreteComponent implements Component {
operation(): string {
return 'ConcreteComponent';
}
}
class Decorator implements Component {
protected component: Component;
constructor(component: Component) {
this.component = component;
}
operation(): string {
return this.component.operation();
}
}
class ConcreteDecoratorA extends Decorator {
operation(): string {
return `ConcreteDecoratorA(${super.operation()})`;
}
}
class ConcreteDecoratorB extends Decorator {
operation(): string {
return `ConcreteDecoratorB(${super.operation()})`;
}
}
const simple = new ConcreteComponent();
console.log(simple.operation());
const decoratedA = new ConcreteDecoratorA(simple);
console.log(decoratedA.operation());
const decoratedB = new ConcreteDecoratorB(decoratedA);
console.log(decoratedB.operation());
4. Cách Khai Báo Decorator Trong TypeScript
Trong TypeScript, Decorator được khai báo bằng ký hiệu @
theo sau là tên hàm decorator. Có bốn loại decorator chính như sau:
- Class Decorator: Áp dụng cho các class.
- Method Decorator: Áp dụng cho các method của class.
- Property Decorator: Áp dụng cho các property của class.
- Parameter Decorator: Áp dụng cho các parameter của method trong class.
Ví Dụ Về Các Kiểu Decorator
a. Class Decorator
Class Decorator được sử dụng để thêm hoặc thay đổi hành vi của một class.
typescript
function sealed(constructor: Function) {
Object.seal(constructor);
Object.seal(constructor.prototype);
}
@sealed
class Greeter {
greeting: string;
constructor(message: string) {
this.greeting = message;
}
greet() {
return `Hello, ${this.greeting}`;
}
}
b. Method Decorator
Method Decorator thay đổi hành vi của một method.
typescript
function enumerable(value: boolean) {
return function (target: any, propertyKey: string, descriptor: PropertyDescriptor) {
descriptor.enumerable = value;
};
}
class Greeter {
greeting: string;
constructor(message: string) {
this.greeting = message;
}
@enumerable(false)
greet() {
return `Hello, ${this.greeting}`;
}
}
c. Property Decorator
Property Decorator thay đổi hành vi của một property.
typescript
function logProperty(target: any, key: string) {
let _val = target[key];
const getter = () => {
console.log(`Get: ${key} => ${_val}`);
return _val;
};
const setter = (newVal) => {
console.log(`Set: ${key} => ${newVal}`);
_val = newVal;
};
Object.defineProperty(target, key, {
get: getter,
set: setter,
enumerable: true,
configurable: true
});
}
class Greeter {
@logProperty
greeting: string;
constructor(message: string) {
this.greeting = message;
}
greet() {
return `Hello, ${this.greeting}`;
}
}
d. Parameter Decorator
Parameter Decorator thay đổi hành vi của một parameter trong method.
typescript
function logParameter(target: any, key: string, index: number) {
const metadataKey = `__log_${key}_parameters`;
if (Array.isArray(target[metadataKey])) {
target[metadataKey].push(index);
} else {
target[metadataKey] = [index];
}
}
class Greeter {
greeting: string;
constructor(message: string) {
this.greeting = message;
}
greet(@logParameter message: string) {
return `Hello, ${message}`;
}
}
5. Ứng Dụng Của Decorator Trong TypeScript
Decorator trong TypeScript đã được áp dụng rộng rãi trong nhiều framework và thư viện nổi tiếng như Angular, NestJS, TypeORM, và nhiều công cụ khác.
- Angular: Sử dụng để định nghĩa các component, service, và thành phần khác của ứng dụng.
- NestJS: Sử dụng để định nghĩa các controller, service, và module.
- TypeORM: Sử dụng để định nghĩa các entity và mối quan hệ giữa chúng.
6. Kết Luận
Decorator trong TypeScript là công cụ mạnh mẽ giúp mở rộng và thay đổi hành vi của class, method, property và parameter mà không cần sửa đổi code gốc. Việc sử dụng Decorator giúp làm cho mã nguồn dễ hiểu và bảo trì hơn. Hy vọng bài viết này đã cung cấp cho bạn cái nhìn rõ ràng về Decorator và cách áp dụng chúng trong TypeScript.
source: viblo