TypeScript 類別 (Class)
雖然現代 React/Vue 開發比較少用 Class,但在寫 Node.js 後端(如 NestJS)或封裝複雜邏輯時,Class 還是非常好用的。
TypeScript 的 Class 語法基本上跟 ES6 Class 一樣,但多了三個強大的功能:存取修飾子、屬性初始化簡寫 和 抽象類別。
存取修飾子 (Access Modifiers)
這大概是 TS Class 最實用的功能了。我們可以控制誰能「看到」或「修改」類別裡的東西。
你可以把類別想像成一間「公司大樓」:
1. public (公開) - 大廳
任何人都可以直接進去,完全沒管制。這是預設值,如果你不寫修飾子,就是 public。
class Employee {
public name: string; // 其實可以省略 public
constructor(name: string) {
this.name = name;
}
}
const e = new Employee('Alice');
console.log(e.name); // OK,外部可以存取
2. private (私有) - 你的私人置物櫃
只有你自己(類別內部)可以打開,其他人(外部程式、甚至是繼承你的子類別)都不能碰。
class BankAccount {
private balance: number;
constructor(initial: number) {
this.balance = initial;
}
// 只能透過公開的方法來存取
getBalance() {
return this.balance;
}
}
const account = new BankAccount(1000);
// account.balance; // 錯誤!balance 是私有的
注意:TypeScript 的
private只是「編譯時期」的檢查。編譯成 JavaScript 後,這些屬性其實還是可以被存取的(雖然會有紅線警告)。如果你需要執行時期真正的私有屬性,請使用 JavaScript 原生的#語法(如#balance)。
3. protected (受保護) - 員工辦公區
外部人員不能進來,但是「員工」(繼承的子類別)可以進來使用。
class Person {
protected id: number = 123;
}
class Employee extends Person {
showId() {
console.log(this.id); // OK,子類別可以存取
}
}
const p = new Person();
// p.id; // 錯誤!外部不能存取
屬性初始化簡寫 (Shorthand Initialization)
這是這寫 TS Class 最爽的功能。
傳統寫法非常囉唆:
- 先宣告屬性型別
- 在建構子宣告參數
- 在建構子裡
this.x = x
// ❌ 傳統寫法 (太長了!)
class Point {
public x: number;
public y: number;
constructor(x: number, y: number) {
this.x = x;
this.y = y;
}
}
✅ 簡寫法:直接在建構子參數前加修飾子 (public, private, readonly),TS 就會自動幫你宣告屬性並賦值。
class Point {
// 自動宣告 x, y 屬性,並自動賦值
constructor(
public x: number,
public y: number
) {}
}
const p = new Point(10, 20);
console.log(p.x); // 10
這在 Dependency Injection (DI) 模式(如 NestJS, Angular)中非常常用。
唯讀屬性 (readonly)
如果你希望某個屬性在初始化後就不能再被修改,可以加上 readonly。
class User {
constructor(
public readonly id: string,
public name: string
) {}
}
const u = new User('A001', 'Alice');
u.name = 'Bob'; // OK
// u.id = "A002"; // 錯誤!id 是唯讀的
靜態成員 (static)
static 屬性或方法是屬於「類別本身」的,而不是屬於「實例 (Instance)」的。通常用來放一些工具函式。
class MathUtil {
static readonly PI = 3.14;
static calculateArea(radius: number) {
return this.PI * radius * radius;
}
}
console.log(MathUtil.PI); // 不需要 new MathUtil() 就可以用