前言
今天來研究研究 TS 中 Class 的細節

Class 是什麼?
在TypeScript(TS) 中,class用於定義物件導向程式設計中的類別。與 JavaScript 相比,TypeScript 的 class 具有一些特別的功能和優點
- 靜態類型檢查
- 封裝和訪問修飾詞
- 建構函式和初始化器
- 繼承和多型
- 抽象類別和介面
- 存取器(Accessors)
| 特點 | 說明 |
|---|---|
| 靜態類型檢查 | TypeScript 提供強大的型別檢查,可在類別的屬性、方法和建構函式上聲明型別,以確保程式碼的正確性。 |
| 封裝和訪問修飾詞 | 使用訪問修飾詞(public、private、protected)來控制屬性和方法的可訪問性,確保只有適當的程式碼可以訪問和修改類別的內部狀態。 |
| 建構函式和初始化器 | 類別中的建構函式(constructor)在建立類別實例時被調用,可用於初始化屬性或執行其他必要的操作。 |
| 繼承和多型 | 類別可以透過繼承機制建立繼承關係,子類別可以繼承父類別的屬性和方法,並進行擴充和覆寫,提供程式碼的重用和組織的靈活性。 |
| 抽象類別和介面 | TypeScript 支援抽象類別和介面的定義。抽象類別不能被實例化,但可以作為其他類別的基類,而介面定義了一組合約,類別可以實現這些介面以確保符合特定的結構。 |
| 存取器(Accessors) | 使用 get 和 set 存取器來設置和獲取類別的屬性值,可對屬性的存取進行更多控制,例如執行額外的邏輯或驗證。 |
TypeScript 和 JavaScript 中 class 的差異
| 功能 | TypeScript (TS) | JavaScript (JS) |
|---|---|---|
| 靜態型別檢查 | 支援靜態型別檢查,可在編譯時檢測並捕獲許多錯誤。 | 沒有內建的靜態型別檢查機制。 |
| 型別註解和型別推斷 | 可以聲明變數、函式和物件的型別,並且進行型別推斷。 | 可以聲明變數的型別,但沒有內建的型別推斷機制。 |
| 類別和模組 | 支援類別和模組的原生語法,可使用 class 和 module 關鍵字。 |
沒有內建的類別和模組語法,使用原型和函式進行物件導向編程。 |
| 介面和抽象類別 | 支援介面和抽象類別的定義,用於描述物件的結構和行為。 | 沒有內建的介面和抽象類別語法,通常使用原型和函式來實現相似的功能。 |
| 可選參數和預設參數 | 可以將函式的參數設置為可選的 ? 符號標記,並指定預設值。 |
可以模擬可選參數和預設參數,但沒有內建的語法支援。 |
| 存取修飾詞 | 支援存取修飾詞(public、private、protected)來控制屬性和方法的訪問權限。 |
沒有內建的存取修飾詞,所有屬性和方法都是公開的。 |
| 繼承和多型 | 支援類別之間的繼承關係,子類別可以繼承父類別的屬性和方法。 | 支援原型鏈繼承,但沒有內建的語法支援類別之間的繼承。 |
| 建構函式和初始化器 | 可以在類別中定義建構函式(constructor),用於初始化 |
使用方式
定義類的關鍵字為class,後面緊跟類名,Class 可以包含以下幾個模塊(Class 的數據成員):
字段: 字段是類裡面聲明的變量。字段表示對象的有關數據。構造函數: 類實例化時調用,可以為類的對象分配內存。方法: 方法為對像要執行的操作
1 | class Car { |
繼承
Class的繼承使用過extends的關鍵字
1 | class Animal { |
Dog是一個派生類,它派生自 Animal 基類,派生類通常被稱作子類,基類通常被稱作超類
Dog類繼承了 Animal 類,因此實例dog也能夠使用 Animal 類 move 方法
同樣,類繼承後,子類可以對父類的方法重新定義,這個過程稱之為方法的重寫,通過 super 關鍵字是對父類的直接引用,該關鍵字可以引用父類的屬性和方法,如下:
1 | class PrinterClass { |
修飾詞
可以看到,上述的形式跟ES6十分的相似,typescript在此基礎上添加了三種修飾詞 :
公共public:可以自由的訪問類程序裡定義的成員私有private:只能夠在該類的內部進行訪問受保護protect:除了在該類的內部可以訪問,還可以在子類中仍然可以訪問
私有修飾詞
只能夠在該類的內部進行訪問,實例對象並不能夠訪問

並且繼承該類的子類並不能訪問,如下圖所示:

受保護修飾詞
跟私有修飾詞很相似,實例對象同樣不能訪問受保護的屬性,如下:

有一點不同的是
protected成員在子類中仍然可以訪問

除了上述修飾詞外,還有唯讀修飾詞
唯讀修飾詞
通過readonly關鍵字進行聲明,唯讀屬性必須在聲明時或構造函數里被初始化,如下:

除了實體屬性 還有靜態屬性
靜態屬性
這些屬性存在於Class本身上面而不是Class的實例上,通過static進行定義,訪問這些屬性需要通過類型.靜態屬性的這種形式訪問,如下所示:
1 | class Square { |
上述的
Class都能發現一個特點就是,都能夠被實例化,在typescript中,還存在一種抽像類
抽像類
抽像類做為其它派生類的基類使用,它們一般不會直接被實例化,不同於接口,抽像類可以包含成員的實現細節
abstract關鍵字是用於定義抽像類和在抽像類內部定義抽象方法,如下所示:
1 | abstract class Animal { |
這種類並不能被實例化,通常需要我們創建子類去繼承,如下:
1 | class Cat extends Animal { |
應用場景
除了日常藉助類的特性完成日常業務代碼,還可以將類(class)也可以作為接口,尤其在 React 中是很常用的,如下:
1 | export default class Carousel extends React.Component<Props, State> {} |
由於組件需要傳入 props 的類型Props,同時有需要設置默認 props 即defaultProps,這時候更加適合使用class作為接口
先聲明一個類,這個類包含組件 props 所需的類型和初始值:
1 | // props的类型 |
當我們需要傳入 props 類型的時候直接將 Props 作為接口傳入,此時 Props 的作用就是接口,而當需要我們設置defaultProps初始值的時候,我們只需要:
1 | public static defaultProps = new Props() |
Props的實例就是defaultProps的初始值,
這就是 `class` 作為接口的實際應用,
我們用一個 `class` 起到了接口和設置初始值兩個作用,
方便統一管理,減少了代碼量