ข้ามไปยังเนื้อหา

this Types & Polymorphism

ภายใน class this ไม่ได้เป็นแค่ value — เป็น type ที่หมายถึง “type ของ instance ปัจจุบัน” และที่สำคัญคือใน subclass this หมายถึง subclass ไม่ใช่ class ที่ method นั้นถูกเขียนไว้ นี่คือ polymorphic this type และทำให้ fluent API ทำงานถูกต้องข้าม inheritance

builder ที่ return this จากแต่ละ method ทำให้ call ต่อกันเป็น chain ได้ การ type return เป็น this (ไม่ใช่ชื่อ class) แปลว่า method ของ subclass ยัง chain ต่อได้

class QueryBuilder {
private parts: string[] = [];
where(cond: string): this { // return type is `this`, not QueryBuilder
this.parts.push(cond);
return this;
}
}
class MySQLBuilder extends QueryBuilder {
limit(n: number): this {
return this;
}
}
new MySQLBuilder()
.where("a = 1") // returns MySQLBuilder (because of `this`), so...
.limit(10); // ...limit() is still available. ✅

ถ้า where ถูก type ให้ return QueryBuilder chain จะ “ลืม” ว่าเป็น MySQLBuilder และ .limit() จะ fail polymorphic this รักษา type จริงไว้ตลอด chain

function สามารถ declare parameter ตัวแรกปลอม ๆ ชื่อ this เพื่อ type ว่า this ต้องเป็นอะไรตอน function ถูกเรียก parameter นี้ถูก erase ตอน emit และไม่กระทบ argument list จริง มีไว้ type-check calling context ล้วน ๆ

interface Card { title: string; }
function render(this: Card) {
return this.title.toUpperCase();
}
// render(); // ❌ The 'this' context of type 'void' is not assignable...
render.call({ title: "hi" }); // ✅ this is a Card here

อันนี้จับ bug ทั้งกลุ่มที่ method พึ่ง this ที่อาจไม่ได้รับจริง

footgun คลาสสิกของ JavaScript — ส่ง method เป็น callback แล้วเสีย this — มีเรื่องราวระดับ type ด้วย เมื่อคุณส่ง obj.method แบบ by reference this binding จะหลุด

class Counter {
count = 0;
increment() { this.count++; } // relies on `this`
}
const c = new Counter();
const fn = c.increment;
// fn(); // 💥 at runtime `this` is undefined

TypeScript จับอันนี้ได้เมื่อคุณ opt in ตัว strictBindCallApply และ (ด้วย this parameter) checker จะ flag การเรียก method ที่ไม่ได้ bind วิธีแก้แบบ idiomatic คือใช้ arrow-function field (increment = () => { ... } ซึ่ง bind this แบบ lexical) หรือ bind ที่จุดเรียก (c.increment.bind(c))

type `this` ภายใน method ของ class หมายถึงอะไร?
ทำไมต้อง return `this` (แทนชื่อ class) จาก builder method ที่ chain ได้?
`this` parameter ใช้ทำอะไร?
วิธีแก้แบบ idiomatic เมื่อ method เสีย `this` ตอนถูกส่งเป็น callback คืออะไร?