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

Classes, Deep

TypeScript มีสองวิธีทำให้ member เป็น private และทั้งสองไม่เหมือนกัน

class Account {
private balance = 0; // compile-time only — erased
#pin = "1234"; // truly private — enforced at runtime
check() {
return this.balance + Number(this.#pin);
}
}
const a = new Account();
// a.balance; // ❌ compile error, but...
// (a as any).balance; // ✅ reachable at runtime — private was erased
// a.#pin; // ❌ SyntaxError even at runtime — hard private
  • private (และ protected) เป็น access check ตอน compile time และถูก erase ตอน emit ดังนั้นคนที่ตั้งใจจริงยังเข้าถึง field ตอน runtime ได้ผ่าน any หรือ bracket access modifier พวกนี้บอก intent และจับ mistake ที่ตั้งใจดี
  • field #name เป็น ECMAScript private field — เข้าถึงจากนอก class ไม่ได้จริง ๆ บังคับโดย JavaScript engine เอง ใช้ # เมื่อ privacy ต้อง hold ตอน runtime

protected อยู่ตรงกลาง: เข้าถึงได้ใน class และ subclass ของตัวเอง แต่ไม่ได้จากข้างนอก

readonly อนุญาตให้ assign ได้แค่ตอน declaration หรือใน constructor แล้ว lock field นั้น เหมือน private เป็น compile-time guarantee — ถูก erase ตอน runtime

class Point {
readonly x: number;
constructor(x: number) {
this.x = x; // ✅ allowed in the constructor
}
move() {
// this.x = 5; // ❌ Cannot assign to 'x' because it is read-only.
}
}

การ declare field แล้ว assign จาก constructor parameter เกิดบ่อยมากจน TypeScript มี shorthand: ใส่ access modifier บน constructor parameter แล้ว parameter นั้นจะกลายเป็น field อัตโนมัติ

class User {
constructor(
public readonly id: string,
private name: string,
) {}
// No separate field declarations, no `this.id = id` — the modifiers do it.
}

อันนี้เท่ากับการ declare id และ name เป็น field แล้ว assign ใน body เป็นแค่ความสะดวก แต่เป็นความสะดวกที่ใช้กันกว้างขวาง

static member เป็นของ ตัว class เอง ไม่ใช่ของ instance มีอยู่จริงตอน runtime เป็น property บน constructor function

class Circle {
static readonly PI = 3.14159;
static area(r: number) { return Circle.PI * r * r; }
}
Circle.area(2); // called on the class, not an instance

abstract class instantiate ตรง ๆ ไม่ได้ มีไว้ให้ extend abstract method declare signature ที่ subclass ต้อง implement ตัว marker abstract เป็น compile-time only

abstract class Shape {
abstract area(): number; // no body — subclasses must provide one
describe() { return `area is ${this.area()}`; } // concrete method
}
// new Shape(); // ❌ Cannot create an instance of an abstract class.
class Square extends Shape {
constructor(private side: number) { super(); }
area() { return this.side * this.side; } // required
}

class implements interface ได้ อันนี้ ไม่ได้ copy อะไรเข้ามา — เป็น assertion ตอน compile time ว่า class satisfy interface เชิง structural เพราะ TypeScript เป็น structural class match interface ได้ โดยไม่ต้อง implements clause แค่ทำให้ intent ชัดเจนและเปลี่ยน mismatch ให้เป็น error ที่จุดนิยาม class แทนที่จะเป็นที่จุดใช้งาน

interface Named { name: string; }
class Product implements Named {
name = "widget"; // if this were missing, the error points HERE
}
ความต่างสำคัญระหว่าง `private balance` กับ `#pin` คืออะไร?
parameter property (เช่น `constructor(public id: string)`) ทำอะไร?
`static` member อยู่ที่ไหน?
`implements Named` จริง ๆ แล้วทำอะไร?