Trình trang trí trong TypeScript

Trình trang trí trong TypeScript

Bài viết này giải thích về trình trang trí trong TypeScript.

YouTube Video

Trình trang trí trong TypeScript

Trình trang trí trong TypeScript là một cơ chế để thêm chức năng hoặc hành vi bổ sung vào các lớp, phương thức, truy cập viên, thuộc tính hoặc tham số. Trình trang trí là một công cụ mạnh mẽ để cải thiện khả năng đọc và tái sử dụng mã nguồn.

Cơ bản về trình trang trí

Trình trang trí là một hàm mà thêm chức năng bổ sung vào lớp hoặc các thành phần của lớp. Trình trang trí được giới thiệu trong TypeScript phiên bản 1.5 và cũng đã được đề xuất vào tiêu chuẩn ECMAScript.

1{
2  "compilerOptions": {
3    "experimentalDecorators": true
4  }
5}
  • Để sử dụng trình trang trí, bạn cần kích hoạt tùy chọn experimentalDecorators trong tệp tsconfig.json.

Các loại trình trang trí

Trong TypeScript, bạn có thể sử dụng năm loại trình trang trí sau.

  • Trình trang trí Lớp Một trình trang trí được áp dụng cho một lớp.
  • Trình trang trí Phương thức Một trình trang trí được áp dụng cho một phương thức của lớp.
  • Trình trang trí Truy cập Một trình trang trí được áp dụng cho getter hoặc setter của thuộc tính lớp.
  • Trình trang trí Thuộc tính Một trình trang trí được áp dụng cho một thuộc tính của lớp.
  • Trình trang trí Tham số Một trình trang trí được áp dụng cho một tham số của phương thức.

Trình trang trí lớp

Trình trang trí lớp là những trình trang trí được áp dụng cho các lớp. Trình trang trí lớp được viết ngay phía trên định nghĩa lớp và có thể truy cập vào hàm tạo của lớp. Chúng chủ yếu được sử dụng để thay đổi hành vi của lớp hoặc thêm siêu dữ liệu.

 1function Logger(constructor: Function) {
 2    console.log(`Class ${constructor.name} is being constructed`);
 3}
 4
 5@Logger
 6class Person {
 7    constructor(public name: string) {}
 8}
 9
10const person = new Person('John');
11// Output: Class Person is being constructed

Trong ví dụ này, trình trang trí Logger được áp dụng cho lớp, và một thông báo sẽ được hiển thị trên bảng điều khiển khi lớp được khởi tạo.

Trình trang trí phương thức

Trình trang trí phương thức được áp dụng cho các phương thức của lớp và có thể thay đổi các lệnh gọi phương thức và hành vi. Một trình trang trí phương thức nhận ba đối số.

  1. Nguyên mẫu của lớp
  2. Tên của phương thức
  3. Mô tả thuộc tính của phương thức
 1function LogExecutionTime(target: any, propertyKey: string, descriptor: PropertyDescriptor) {
 2    const originalMethod = descriptor.value;
 3
 4    descriptor.value = function (...args: any[]) {
 5        console.time(propertyKey);
 6        const result = originalMethod.apply(this, args);
 7        console.timeEnd(propertyKey);
 8        return result;
 9    };
10}
11
12class MathOperations {
13  @LogExecutionTime
14  add(a: number, b: number): number {
15    return a + b;
16  }
17}
18
19const math = new MathOperations();
20math.add(2, 3);
21// Output: add: 0.000ms (execution time is displayed)

Trong ví dụ này, decorator LogExecutionTime được áp dụng cho phương thức và thời gian thực thi của phương thức được ghi lại.

Decorator Truy cập

Các decorator truy cập được áp dụng cho getter hoặc setter của thuộc tính lớp. Chúng hữu ích để thêm hành vi khi thay đổi giá trị thuộc tính.

 1function LogAccess(target: any, propertyKey: string, descriptor: PropertyDescriptor) {
 2    const originalGet = descriptor.get;
 3    const originalSet = descriptor.set;
 4
 5    if (originalGet) {
 6        descriptor.get = function () {
 7            console.log(`Getter called for ${propertyKey}`);
 8            return originalGet.call(this);
 9        };
10    }
11
12    if (originalSet) {
13        descriptor.set = function (value: any) {
14            console.log(`Setter called for ${propertyKey} with value: ${value}`);
15            originalSet.call(this, value);
16        };
17    }
18}
19
20class Car {
21    private _speed: number = 0;
22
23    @LogAccess
24    get speed() {
25        return this._speed;
26    }
27
28    set speed(value: number) {
29        this._speed = value;
30    }
31}
32
33const car = new Car();
34car.speed = 120;               // Setter called for speed with value: 120
35console.log(car.speed);       // Getter called for speed → 120

Trong ví dụ này, một decorator truy cập được sử dụng để ghi nhật ký đầu ra khi gettersetter được gọi.

Decorator Thuộc tính

Các decorator thuộc tính được áp dụng cho thuộc tính lớp nhưng không thể trực tiếp thay đổi giá trị hoặc hành vi của thuộc tính. Chúng được sử dụng để lấy siêu dữ liệu của thuộc tính.

 1function Readonly(target: any, propertyKey: string) {
 2    Object.defineProperty(target, propertyKey, {
 3        writable: false
 4    });
 5}
 6
 7class Book {
 8    @Readonly
 9    title: string = "TypeScript Guide";
10}
11
12const book = new Book();
13book.title = "New Title"; // Error: Cannot assign to read only property 'title'

Trong ví dụ này, decorator Readonly được áp dụng cho thuộc tính title, và thuộc tính trở thành chỉ đọc.

Decorator Tham số

Các decorator tham số được áp dụng cho tham số của phương thức. Chúng thường được sử dụng để lưu trữ siêu dữ liệu hoặc xác thực tham số. Decorator nhận ba tham số.

  1. Nguyên mẫu của lớp
  2. Tên của phương thức
  3. Chỉ số Tham số
 1function LogParameter(target: any, propertyKey: string, parameterIndex: number) {
 2    console.log(`Parameter at index ${parameterIndex} in method ${propertyKey} was decorated.`);
 3}
 4
 5class User {
 6    greet(@LogParameter message: string) {
 7        console.log(message);
 8    }
 9}
10
11const user = new User();
12user.greet('Hello!');
13// Output: Parameter at index 0 in method greet was decorated.

Trong ví dụ này, decorator LogParameter được áp dụng cho tham số đầu tiên của phương thức greet, và khi phương thức được gọi, nó sẽ ghi nhận rằng tham số được trang trí.

Ví dụ Thực tế về Decorator

Các decorator được sử dụng rộng rãi trong các framework như Angular, đặc biệt để tiêm phụ thuộc và định nghĩa siêu dữ liệu. Ví dụ, sử dụng decorator @Component để định nghĩa các thành phần Angular như dưới đây.

1@Component({
2    selector: 'app-root',
3    template: '<h1>Hello World</h1>',
4})
5export class AppComponent {}

Do đó, các decorator thường được sử dụng như các phần cốt lõi của framework và thư viện, giúp giữ mã nguồn gọn gàng và rõ ràng.

Tóm tắt về Decorator

Các decorator trong TypeScript là công cụ mạnh mẽ có thể linh hoạt thêm chức năng vào lớp, phương thức và thuộc tính. Việc sử dụng các decorator tùy chỉnh cải thiện khả năng bảo trì và tái sử dụng mã, đồng thời cho phép trừu tượng hóa thêm. Decorators đóng vai trò quan trọng trong các framework như Angular và NestJS, và việc hiểu chúng giúp hiểu sâu hơn cách các framework này hoạt động.

Bạn có thể làm theo bài viết trên bằng cách sử dụng Visual Studio Code trên kênh YouTube của chúng tôi. Vui lòng ghé thăm kênh YouTube.

YouTube Video