TypeScript - Trang trí

Xin chào các bạn đang học lập trình! Hôm nay, chúng ta sẽ bắt đầu một hành trình thú vị vào thế giới của cácDecorator trong TypeScript. Đừng lo lắng nếu bạn là người mới bắt đầu lập trình - tôi sẽ hướng dẫn bạn từng bước qua khái niệm này, giống như tôi đã làm cho hàng trăm học sinh trong những năm dạy học của mình. Vậy, chúng ta cùng bắt đầu nhé!

TypeScript - Decorators

Decorators là gì?

Trước khi chúng ta đi vào chi tiết, hãy hiểu Decorators là gì. Hãy tưởng tượng bạn có một chiếc bánh cupcake đơn giản. Decorators giống như những hạt装饰, kem và cherry trên đỉnh làm cho chiếc cupcake của bạn trở nên đặc biệt hơn. Trong TypeScript, decorators thêm chức năng bổ sung vào các lớp, phương thức, thuộc tính và tham số của bạn.

Sử dụng Decorators trong TypeScript

Để bắt đầu sử dụng decorators trong TypeScript, bạn cần启用 chúng trong tệp tsconfig.json của mình. Điều này giống như bật lò trước khi nướng bánh cupcake!

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

Cú pháp Decorator

Bây giờ, hãy xem cách chúng ta viết decorators. Nó đơn giản hơn bạn tưởng tượng!

function simpleDecorator(target: any) {
console.log("Tôi là một decorator đơn giản!");
}

@simpleDecorator
class MyClass {
// Thực thi lớp
}

Trong ví dụ này, simpleDecorator giống như một tem chúng ta dán lên MyClass. Mỗi khi chúng ta sử dụng MyClass, nó sẽ in ra "Tôi là một decorator đơn giản!" lên console.

Nhà máy Decorator

Đôi khi, chúng ta muốn decorators của mình có thể tùy chỉnh. Đó là lúc decorator factories ra vào cuộc. Chúng giống như một máy sản xuất decorators dựa trên yêu cầu của chúng ta.

function decoratorFactory(message: string) {
return function (target: any) {
console.log(message);
}
}

@decoratorFactory("Xin chào, tôi là một decorator tùy chỉnh!")
class MyClass {
// Thực thi lớp
}

Ở đây, decoratorFactory đang tạo một decorator mà in ra tin nhắn tùy chỉnh của chúng ta.

Composition của Decorator

Chúng ta có thể sử dụng nhiều decorators trên một mục tiêu duy nhất. Điều này giống như thêm nhiều topping lên chiếc cupcake của mình!

function first() {
console.log("first(): nhà máy được đánh giá");
return function (target: any, propertyKey: string, descriptor: PropertyDescriptor) {
console.log("first(): được gọi");
};
}

function second() {
console.log("second(): nhà máy được đánh giá");
return function (target: any, propertyKey: string, descriptor: PropertyDescriptor) {
console.log("second(): được gọi");
};
}

class ExampleClass {
@first()
@second()
method() {}
}

Trong trường hợp này, các decorators được áp dụng từ dưới lên: second() sau đó là first().

Tại sao sử dụng Decorators?

Decorators vô cùng hữu ích cho:

  1. Thêm metadata vào mã của bạn
  2. Thay đổi hành vi của các lớp và phương thức
  3. Thực hiện các khía cạnh của Lập trình Hướng Aspects
  4. Tạo mã có thể tái sử dụng mà có thể dễ dàng áp dụng cho nhiều lớp

Decorators Lớp

Decorators lớp được áp dụng cho constructor của lớp và có thể được sử dụng để quan sát, sửa đổi hoặc thay thế định nghĩa của lớp.

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;
}
}

Trong ví dụ này, decorator @sealed ngăn không cho lớp Greeter bị sửa đổi sau khi định nghĩa.

Decorators Phương thức

Decorators phương thức có thể được sử dụng để sửa đổi, quan sát hoặc thay thế định nghĩa của phương thức.

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;
}
}

Ở đây, decorator @enumerable(false) làm cho phương thức greet không thể đếm.

Decorators Truy cập

Decorators truy cập được áp dụng cho property descriptor của truy cập và có thể được sử dụng để quan sát, sửa đổi hoặc thay thế định nghĩa của truy cập.

function configurable(value: boolean) {
return function (target: any, propertyKey: string, descriptor: PropertyDescriptor) {
descriptor.configurable = value;
};
}

class Point {
private _x: number;
private _y: number;
constructor(x: number, y: number) {
this._x = x;
this._y = y;
}

@configurable(false)
get x() { return this._x; }

@configurable(false)
get y() { return this._y; }
}

Trong ví dụ này, decorator @configurable(false) làm cho các truy cập xy không thể cấu hình.

Decorators Thuộc tính

Decorators thuộc tính được sử dụng để quan sát, sửa đổi hoặc thay thế định nghĩa của thuộc tính.

function format(formatString: string) {
return function (target: any, propertyKey: string): any {
let value = target[propertyKey];

const getter = function () {
return `${formatString} ${value}`;
};

const setter = function (newVal: string) {
value = newVal;
};

return {
get: getter,
set: setter,
enumerable: true,
configurable: true
};
};
}

class Greeter {
@format("Hello,")
greeting: string;
}

const greeter = new Greeter();
greeter.greeting = "World";
console.log(greeter.greeting); // Xuất: "Hello, World"

Ở đây, decorator @format thêm tiền tố vào thuộc tính greeting.

Decorators Tham số

Decorators tham số được sử dụng để quan sát, sửa đổi hoặc thay thế định nghĩa của tham số.

function required(target: Object, propertyKey: string | symbol, parameterIndex: number) {
let existingRequiredParameters: number[] = Reflect.getOwnMetadata("required", target, propertyKey) || [];
existingRequiredParameters.push(parameterIndex);
Reflect.defineMetadata("required", existingRequiredParameters, target, propertyKey);
}

class Greeter {
greet(@required name: string) {
return "Hello " + name;
}
}

Trong ví dụ này, decorator @required đánh dấu tham số name là bắt buộc.

Phương thức Decorator

Dưới đây là bảng tóm tắt các loại decorators và phương thức của chúng:

Loại Decorator Phương thức
Class Decorator declare type ClassDecorator = <TFunction extends Function>(target: TFunction) => TFunction | void;
Method Decorator declare type MethodDecorator = <T>(target: Object, propertyKey: string | symbol, descriptor: TypedPropertyDescriptor<T>) => TypedPropertyDescriptor<T> | void;
Accessor Decorator declare type AccessorDecorator = <T>(target: Object, propertyKey: string | symbol, descriptor: TypedPropertyDescriptor<T>) => TypedPropertyDescriptor<T> | void;
Property Decorator declare type PropertyDecorator = (target: Object, propertyKey: string | symbol) => void;
Parameter Decorator declare type ParameterDecorator = (target: Object, propertyKey: string | symbol, parameterIndex: number) => void;

Và đó là tất cả! Chúng ta đã bao gồm các основ của decorators trong TypeScript. Nhớ rằng, giống như học nướng bánh cupcake hoàn hảo, việc thành thạo decorators cũng cần sự luyện tập. Đừng ngại thử nghiệm và mắc lỗi - đó là cách chúng ta học hỏi và phát triển như những nhà lập trình. Chúc các bạn lập trình vui vẻ!

Credits: Image by storyset