refactor: typescript 5 decorator #5
Merged
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
TypeScript 實戰:後端裝飾器生成路由
前言
在這篇文章中,我們將介紹如何使用 TypeScript 的裝飾器來生成 Express 路由,從而讓程式碼更加簡潔。過去,由於 TypeScript 的裝飾器功能尚未完善,我們通常需要使用
reflect-metadata
這樣的套件來擴展裝飾器對metadata
的支援。然而,隨著 TypeScript 5.2 的推出,裝飾器已經原生支援metadata
,因此不需要再依賴外部套件。不過,請注意,目前 JavaScript 還沒有完全支援
Symbol.metadata
,所以在 TypeScript 中使用這些功能時仍然需要一些注意。建議在等 JavaScript 完全支援後再使用這些功能到正式的產品環境中。若在使用裝飾器的

metadata
時遇到以下錯誤:你需要在 tsconfig 中加入如下配置,以支援最新的裝飾器功能:
實作裝飾器
實作 Controller 的裝飾器
我們首先實作一個 Controller 裝飾器,來指定每個 Controller 的基礎路徑(basePath),並儲存在
metadata
中供之後的路由註冊使用。實作 Method 的裝飾器
接下來,我們將為常見的 HTTP 方法(如:
GET
、POST
、PUT
、DELETE
)實作對應的裝飾器,這些裝飾器會將每個路由的資訊存入metadata
,以便後續自動生成 Express 路由。我們首先定義常見的 HTTP 方法:
接著,我們使用 zod 套件來定義路由配置的資料結構,確保所有保存至
metadata
中的資料符合預期的格式。為了在註冊路由前驗證
metadata
,我們可以定義一個 validateMetadata 函式來解析目標類別的metadata
,並使用 zod 進行資料驗證。接下來,我們實作一個工廠函式的
methodDecoratorFactory
,透過此函式生成不同 HTTP 方法對應的裝飾器。這些裝飾器會將方法、路徑和處理函數名稱一併儲存到 metadata 中。最後,我們使用
methodDecoratorFactory
生成對應的 HTTP 方法裝飾器:重構 Controller
接下來,我們將實際使用這些裝飾器,來重構 Controller。以往,我們使用函式式的方式來撰寫路由定義,現在可以將它重構為類別,並使用裝飾器。
收攏 Controller
接著我們將所有 Controller 都引入到
src/controllers/index.ts
。未來我們新增新的 Controller 後,只需將它們加入 controllers 陣列,就會自動生成對應的 Router。
重構 Routes
我們可以刪除之前手動撰寫的 Routes,並在主程式
main.ts
中動態註冊 Controller 的路由。以下是在
main.ts
中的註冊方式:這樣一來,我們就可以動態註冊所有 Controller 的路由,並在主程式中統一處理錯誤,使程式碼更加模組化。
添加 Polyfill
如果當初設定 tsconfig 有設定
ESNext.Decorators
的話,如果打包成 JavaScript 會因為沒有Symbol.metadata
而導致伺服器無法啟動,這時我們要自己寫 Polyfill 來支援Symbol.metadata
如下:解法來源:microsoft/TypeScript#53461 (comment)
並在有實作
metadata
的裝飾器檔案引入這個 polyfill 檔案總結
在這篇文章中,我們使用了 TypeScript 的裝飾器來自動生成路由,大幅簡化了手動設定路由的繁瑣步驟。通過使用裝飾器,我們可以讓每個 Controller 的定義更加清晰,未來想新增 API 就只要新增對應的 Model 和 Controller,Router 會自動根據裝飾器生成,那這系列後端實戰的部分就到這裡,下一篇會介紹如何在前端 React 中使用 TypeScript,並串接我們實作的後端!