ตัวตกแต่งใน 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
ถูกนำไปใช้กับคลาส และจะแสดงข้อความในคอนโซลเมื่อคลาสถูกเริ่มต้น
ตัวตกแต่งเมธอด
ตัวตกแต่งเมธอดถูกใช้กับเมธอดของคลาสและสามารถเปลี่ยนแปลงการเรียกใช้เมธอดและพฤติกรรมได้ ตัวตกแต่งเมธอดจะรับอาร์กิวเมนต์สามค่า
- แม่แบบของคลาส
- ชื่อของเมธอด
- ตัวระบุคุณสมบัติของเมธอด
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
และคุณสมบัติจะถูกทำให้เป็นแบบอ่านได้อย่างเดียว
ตัวตกแต่งพารามิเตอร์
ตัวตกแต่งพารามิเตอร์จะถูกใช้กับพารามิเตอร์ของเมธอด พวกมันมักจะถูกใช้เพื่อจัดเก็บข้อมูลเมตาหรือประเมินพารามิเตอร์ ตัวตกแต่งจะรับอาร์กิวเมนต์สามตัว
- แม่แบบของคลาส
- ชื่อของเมธอด
- ดัชนีพารามิเตอร์
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 ด้วย