Decorators
decorator มีสองยุค — ใช้ยุคใหม่
หัวข้อที่มีชื่อว่า “decorator มีสองยุค — ใช้ยุคใหม่”decorator คือ function ที่ wrap หรือสังเกต class หรือ member ของ class ให้คุณเพิ่ม behavior แบบ declarative ด้วย syntax @name มีสอง design ที่เข้ากันไม่ได้ และสำคัญว่าคุณหมายถึงอันไหน:
- legacy decorator — design เก่าแบบ experimental ที่เปิดด้วย
experimentalDecoratorsในtsconfigใช้เยอะใน Angular และ NestJS รุ่นเก่า signature ต่างกัน และพึ่งreflect-metadata - stage-3 decorator — design ECMAScript ที่เป็นมาตรฐาน รองรับ native ตั้งแต่ TypeScript 5.0 โดยไม่ต้องใช้ flag พิเศษ อันนี้คือตัวที่ควรเรียนสำหรับ code ใหม่
บทเรียนนี้ครอบคลุม decorator แบบ stage-3
method decorator
หัวข้อที่มีชื่อว่า “method decorator”method decorator รับ method ต้นฉบับกับ context object แล้ว return ตัวแทน (หรือไม่ return อะไร) นี่คือ decorator @logged ที่ wrap method เพื่อ log การเรียกของตัวเอง:
function logged(originalMethod: any, context: ClassMethodDecoratorContext) { const name = String(context.name); function replacement(this: any, ...args: any[]) { console.log(`calling ${name}`); return originalMethod.call(this, ...args); } return replacement;}
class Service { @logged fetch(id: number) { return `item ${id}`; }}
new Service().fetch(1); // logs "calling fetch", then returns "item 1"context object คือหัวใจของ design ใหม่ โดยบอก decorator ว่ากำลัง decorate อะไร — context.kind ("method", "field", "getter", …), context.name, context.static, context.private และ hook addInitializer สำหรับงาน setup
สี่สิ่งที่ decorate ได้
หัวข้อที่มีชื่อว่า “สี่สิ่งที่ decorate ได้”| ชนิด decorator | รับอะไร | ใช้ทั่วไป |
|---|---|---|
| Class | ตัว class, context | register class, wrap constructor |
| Method | method, context | wrap/แทน behavior (logging, timing) |
| Accessor | getter/setter, context | ดักการ read/write |
| Field | undefined, context | return initializer เพื่อแปลง initial value |
field decorator ต่างออกไปนิด — ไม่ได้รับ value มา wrap แต่ return initializer function ที่แปลง initial value ของ field เมื่อสร้าง instance ได้
decorator factory
หัวข้อที่มีชื่อว่า “decorator factory”จะทำให้ decorator ตั้งค่าได้ ให้เขียน function ที่ return decorator — เรียกว่า decorator factory การเรียก @name(args) จะรัน factory แล้วค่าที่ return ออกมาคือ decorator จริง
function logged(label: string) { // factory: takes config return function (originalMethod: any, context: ClassMethodDecoratorContext) { return function (this: any, ...args: any[]) { console.log(`[${label}] ${String(context.name)}`); return originalMethod.call(this, ...args); }; };}
class Api { @logged("http") get() { /* ... */ }}