ตัวตกแต่งใน TypeScript

ตัวตกแต่งใน TypeScript

บทความนี้อธิบายตัวตกแต่งใน TypeScript

YouTube Video

ตัวตกแต่งใน TypeScript

ตัวตกแต่งใน TypeScript เป็นกลไกสำหรับการเพิ่มฟังก์ชันการทำงานหรือพฤติกรรมเพิ่มเติมให้กับคลาส, เมธอด, แอ็กเซสเซอร์, คุณสมบัติ หรือพารามิเตอร์ ตัวตกแต่งเป็นเครื่องมือที่ทรงพลังสำหรับการเพิ่มความสามารถในการอ่านและนำโค้ดกลับมาใช้ใหม่

พื้นฐานของตัวตกแต่ง

ตัวตกแต่งคือฟังก์ชันที่เพิ่มฟังก์ชันการทำงานเพิ่มเติมให้กับคลาสหรือสมาชิกของคลาส ตัวตกแต่งถูกแนะนำใน TypeScript 1.5 และยังได้รับการเสนอให้เป็นมาตรฐานของ ECMAScript

1{
2  "compilerOptions": {
3    "experimentalDecorators": true
4  }
5}
  • เพื่อใช้ตัวตกแต่ง คุณต้องเปิดใช้งานตัวเลือก experimentalDecorators ในไฟล์ tsconfig.json

ชนิดของตัวตกแต่ง

ใน TypeScript คุณสามารถใช้ตัวตกแต่งห้าประเภทดังนี้

  • ตัวตกแต่งคลาส ตัวตกแต่งที่ถูกนำมาใช้กับคลาส
  • ตัวตกแต่งเมธอด ตัวตกแต่งที่ถูกนำมาใช้กับเมธอดของคลาส
  • ตัวตกแต่งแอคเซสเซอร์ ตัวตกแต่งที่ถูกนำมาใช้กับ getter หรือ setter ของพร็อพเพอร์ตี้ในคลาส
  • ตัวตกแต่งพร็อพเพอร์ตี้ ตัวตกแต่งที่ถูกนำมาใช้กับพร็อพเพอร์ตี้ของคลาส
  • ตัวตกแต่งพารามิเตอร์ ตัวตกแต่งที่ถูกนำมาใช้กับพารามิเตอร์ของเมธอด

ตัวตกแต่งคลาส

ตัวตกแต่งคลาสคือตัวตกแต่งที่ใช้กับคลาส ตัวตกแต่งคลาสจะถูกเขียนไว้เหนือนิยามคลาสและสามารถเข้าถึงตัวสร้างของคลาสได้ มันถูกใช้หลักในการเปลี่ยนแปลงพฤติกรรมของคลาสหรือเพิ่มเมทาดาต้า

 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

ในตัวอย่างนี้ ตัวตกแต่ง Logger ถูกนำไปใช้กับคลาส และจะแสดงข้อความในคอนโซลเมื่อคลาสถูกเริ่มต้น

ตัวตกแต่งเมธอด

ตัวตกแต่งเมธอดถูกใช้กับเมธอดของคลาสและสามารถเปลี่ยนแปลงการเรียกใช้เมธอดและพฤติกรรมได้ ตัวตกแต่งเมธอดจะรับอาร์กิวเมนต์สามค่า

  1. แม่แบบของคลาส
  2. ชื่อของเมธอด
  3. ตัวระบุคุณสมบัติของเมธอด
 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)

ในตัวอย่างนี้, LogExecutionTime ตัวตกแต่งถูกนำไปใช้กับเมธอด และเวลาที่ใช้ในการดำเนินการของเมธอดจะถูกบันทึก

ตัวตกแต่งตัวเข้าถึง

ตัวตกแต่งตัวเข้าถึงจะนำไปใช้กับ getter หรือ setter ของคุณสมบัติในคลาส พวกมันมีประโยชน์สำหรับการเพิ่มพฤติกรรมเมื่อเปลี่ยนค่าคุณสมบัติ

 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

ในตัวอย่างนี้ มีการใช้ตัวตกแต่งแอกเซสเซอร์เพื่อบันทึกผลลัพธ์เมื่อเรียกใช้ getter และ setter

ตัวตกแต่งคุณสมบัติ

ตัวตกแต่งคุณสมบัตินำไปใช้กับคุณสมบัติในคลาส แต่ไม่สามารถเปลี่ยนแปลงค่าหรือพฤติกรรมของคุณสมบัติโดยตรง พวกมันถูกใช้เพื่อดึงข้อมูลเมตาของคุณสมบัติ

 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'

ในตัวอย่างนี้, ตัวตกแต่ง Readonly ถูกนำมาใช้กับคุณสมบัติ title และคุณสมบัติจะถูกทำให้เป็นแบบอ่านได้อย่างเดียว

ตัวตกแต่งพารามิเตอร์

ตัวตกแต่งพารามิเตอร์จะถูกใช้กับพารามิเตอร์ของเมธอด พวกมันมักจะถูกใช้เพื่อจัดเก็บข้อมูลเมตาหรือประเมินพารามิเตอร์ ตัวตกแต่งจะรับอาร์กิวเมนต์สามตัว

  1. แม่แบบของคลาส
  2. ชื่อของเมธอด
  3. ดัชนีพารามิเตอร์
 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.

ในตัวอย่างนี้, ตัวตกแต่ง LogParameter ถูกนำไปใช้กับพารามิเตอร์ตัวแรกของเมธอด greet และเมื่อเรียกใช้เมธอด, จะบันทึกว่าพารามิเตอร์นั้นถูกตกแต่ง

ตัวอย่างการใช้งานจริงของตัวตกแต่ง

ตัวตกแต่งถูกใช้อย่างแพร่หลายในเฟรมเวิร์กเช่น Angular โดยเฉพาะสำหรับการฉีดพึ่งพาและการกำหนดข้อมูลเมตา ตัวอย่างเช่น, ใช้ตัวตกแต่ง @Component เพื่อกำหนดคอมโพเนนต์ Angular ดังตัวอย่างข้างล่างนี้

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

ดังนั้น, ตัวตกแต่งจึงมักถูกใช้เป็นส่วนสำคัญในเฟรมเวิร์กและไลบรารีต่าง ๆ ช่วยให้โค้ดกระชับและชัดเจน

สรุปเกี่ยวกับตัวตกแต่ง

ตัวตกแต่งใน TypeScript เป็นเครื่องมือที่ทรงพลังที่สามารถเพิ่มฟังก์ชันให้กับคลาส, เมธอด, และคุณสมบัติได้อย่างยืดหยุ่น การใช้ตัวตกแต่งที่สร้างขึ้นเองช่วยปรับปรุงความสามารถในการบำรุงโค้ดและการนำกลับมาใช้ใหม่ พร้อมทั้งสร้างความเป็นนามธรรมเพิ่มเติมได้ ตัวตกแต่ง (Decorators) มีบทบาทสำคัญในเฟรมเวิร์คอย่าง Angular และ NestJS และการทำความเข้าใจเกี่ยวกับตัวตกแต่งจะช่วยให้เข้าใจการทำงานของเฟรมเวิร์คเหล่านี้อย่างลึกซึ้ง

คุณสามารถติดตามบทความข้างต้นโดยใช้ Visual Studio Code บนช่อง YouTube ของเรา กรุณาตรวจสอบช่อง YouTube ด้วย

YouTube Video