Decorators là một tính năng mạnh mẽ trong TypeScript cho phép bạn thêm các hành vi mới vào các lớp, phương thức, thuộc tính, hoặc tham số mà không cần phải thay đổi cấu trúc của chúng. Đây là một phần của các tính năng lập trình hướng đối tượng, giúp bạn tạo ra mã rõ ràng và có thể tái sử dụng. Decorators thường được sử dụng trong các thư viện và framework như Angular, để cấu hình và quản lý các thành phần.

Các loại Decorators

Có nhiều loại decorators trong TypeScript, mỗi loại phục vụ cho các mục đích khác nhau. Dưới đây là các loại decorators chính:

1. Class Decorators

Class decorators được áp dụng cho các lớp. Chúng cho phép bạn thay đổi hoặc mở rộng hành vi của lớp.

function LogClass(target: Function) {
    console.log(`Class: ${target.name}`);
}

@LogClass
class Person {
    constructor(public name: string) {}
}

Trong ví dụ này, decorator LogClass sẽ ghi lại tên của lớp khi lớp Person được khởi tạo. Khi bạn tạo một thể hiện của lớp Person, tên của lớp sẽ được in ra console.

2. Method Decorators

Method decorators cho phép bạn thay đổi hành vi của các phương thức trong lớp.

function LogMethod(target: any, propertyName: string, descriptor: PropertyDescriptor) {
    const originalMethod = descriptor.value;
    descriptor.value = function (...args: any[]) {
        console.log(`Calling method: ${propertyName} with arguments: ${args}`);
        return originalMethod.apply(this, args);
    };
}

class Calculator {
    @LogMethod
    add(a: number, b: number): number {
        return a + b;
    }
}

const calc = new Calculator();
calc.add(5, 10); // Ghi lại: Calling method: add with arguments: 5,10

Trong ví dụ này, decorator LogMethod sẽ ghi lại tên phương thức và các tham số của nó khi phương thức add được gọi.

3. Property Decorators

Property decorators được sử dụng để thay đổi hoặc thêm hành vi cho các thuộc tính trong lớp.

function LogProperty(target: any, propertyName: string) {
    let value = target[propertyName];

    const getter = () => {
        console.log(`Getting value of ${propertyName}: ${value}`);
        return value;
    };

    const setter = (newValue: any) => {
        console.log(`Setting value of ${propertyName} to ${newValue}`);
        value = newValue;
    };

    Object.defineProperty(target, propertyName, {
        get: getter,
        set: setter,
    });
}

class User {
    @LogProperty
    public username: string;

    constructor(username: string) {
        this.username = username;
    }
}

const user = new User("Alice");
user.username = "Bob"; // Ghi lại: Setting value of username to Bob
console.log(user.username); // Ghi lại: Getting value of username: Bob

Trong ví dụ này, decorator LogProperty sẽ ghi lại khi giá trị của thuộc tính username được thiết lập và truy cập.

4. Parameter Decorators

Parameter decorators được áp dụng cho các tham số của phương thức. Chúng cho phép bạn thêm các hành vi bổ sung cho các tham số đó.

function LogParameter(target: any, methodName: string, parameterIndex: number) {
    console.log(`Parameter in method ${methodName} at index ${parameterIndex} has been decorated.`);
}

class UserService {
    greet(@LogParameter name: string): void {
        console.log(`Hello, ${name}!`);
    }
}

const userService = new UserService();
userService.greet("Alice"); // Ghi lại: Parameter in method greet at index 0 has been decorated.

Trong ví dụ này, decorator LogParameter sẽ ghi lại chỉ số của tham số khi phương thức greet được gọi.

Cách sử dụng Decorators

Để sử dụng decorators trong TypeScript, bạn cần phải bật tính năng decorators trong tệp cấu hình tsconfig.json. Bạn có thể làm điều này bằng cách thêm thuộc tính experimentalDecorators và đặt nó thành true:

{
    "compilerOptions": {
        "experimentalDecorators": true
    }
}

Kết luận

Decorators trong TypeScript là một công cụ mạnh mẽ giúp bạn mở rộng và thay đổi hành vi của các lớp, phương thức, thuộc tính, và tham số một cách dễ dàng. Việc sử dụng decorators không chỉ giúp mã của bạn trở nên rõ ràng hơn mà còn tăng cường khả năng tái sử dụng và bảo trì mã. Với tính năng này, bạn có thể viết mã một cách linh hoạt hơn, cải thiện quy trình phát triển và dễ dàng quản lý các thành phần trong ứng dụng của bạn. Hãy khám phá và áp dụng decorators trong các dự án của bạn để tận dụng những lợi ích mà chúng mang lại!