隨著前端技術的不斷發展,現代應用變得愈來愈複雜,開發團隊也愈來愈龐大。這時候,強大的型別系統與模組化結構就顯得至關重要。而 TypeScript,作為 JavaScript 的型別超集,不僅解決了這些挑戰,還提供了工具來提升程式碼的可維護性、可擴展性以及可讀性。
當應用程式逐漸變大,你可能會遇到以下問題:
模組化是解決大型應用可維護性問題的核心手段。透過模組化,我們可以將程式碼拆分成獨立的部分,每一部分負責一個特定的功能。
透過模組化,我們可以:
模組化的好處在於它將不同的業務邏輯分開,使團隊可以並行開發不同模組,減少彼此間的依賴,提升維護和擴展性。
modules/
:用來存放各個功能模組,如 user(用戶模組)、product(產品模組)。shared/
:存放可跨模組使用的共用工具和函數。src/
│
├── modules/
│ ├── user/
│ │ ├── user.controller.ts
│ │ ├── user.service.ts
│ │ └── user.model.ts
│ └── product/
│ ├── product.controller.ts
│ ├── product.service.ts
│ └── product.model.ts
│
└── shared/
└── utils.ts
假設團隊正在開發一個電商平台,其中的購物車功能需要管理商品的增減、總價或折扣後金額計算等邏輯。傳統的做法可能會把這些邏輯都寫在一個大文件中,但這不僅難以維護,也容易出錯。而通過模組化,就可以將不同的功能拆分到不同的模組中。
// cart.ts - 購物車模組
export class Cart {
private items: Array<{ productId: number, quantity: number }> = [];
addItem(productId: number, quantity: number) {
this.items.push({ productId, quantity });
}
removeItem(productId: number) {
this.items = this.items.filter(item => item.productId !== productId);
}
getTotalItems(): number {
return this.items.length;
}
}
這樣,我們就將購物車的邏輯封裝在 Cart
類中,並且可以在其它地方重複使用這個模組。
TypeScript 的模組系統不只可以將程式碼拆分為多個文件,還可以有效地封裝內部邏輯,讓開發者只暴露需要給外部使用的接口,減少耦合,提升模組的複用性。
在 user.service.ts
裡,可以將不必要暴露的邏輯隱藏起來,只提供外部使用的接口:
// user.service.ts
class UserService {
private users = [];
addUser(name: string) {
this.users.push(name);
}
getUsers() {
return this.users;
}
}
export const userService = new UserService();
在這個範例,透過 export
只暴露了 userService
的實例,而沒有暴露其內部數據結構 users
,這樣外部無法直接訪問或修改內部狀態。
在大型應用中,型別管理的作用不容忽視。TypeScript 的靜態型別系統可以讓開發者在編譯階段就捕捉到許多潛在錯誤,這是 JavaScript 無法提供的!TypeScript 的型別還可以幫助進行以下幾點:
假設我們在電商平台中需要管理多種商品類型。透過 TypeScript 的型別,我們可以輕鬆定義並管理不同商品的結構,避免誤用。
interface Product {
id: number;
name: string;
price: number;
}
interface Electronic extends Product {
warranty: number; // 電子商品特有的保固期
}
interface Clothing extends Product {
size: string; // 衣物特有的尺寸
}
使用這樣的型別,我們就可以確保在不同的商品模組中不會發生資料錯置的情況,例如誤將 size
傳給電子商品類型的產品。
當應用程式越來越大時,模組與型別的結合就顯得尤為重要。透過將每個模組的邏輯封裝起來,並對外部提供清晰的型別定義,可以大大提高程式碼的可維護性與易讀性。
在電商平台的購物車中,我們可以這樣結合模組與型別:
interface CartItem {
product: Product;
quantity: number;
}
class Cart {
private items: CartItem[] = [];
addItem(product: Product, quantity: number) {
this.items.push({ product, quantity });
}
getTotalPrice(): number {
return this.items.reduce((total, item) => total + item.product.price * item.quantity, 0);
}
}
在這裡,CartItem
是一個帶有型別的接口,定義了購物車中商品的結構。Cart
類則負責購物車的邏輯運算。通過型別與模組的結合,我們可以明確地知道每個模組應該如何操作、接收哪些參數,這不僅讓程式碼更安全,也減少了開發過程中的溝通成本。
30 天的鐵人挑戰在這一年又告一段落了!雖然有點慢才來分享 TypeScript 的主題,但是秉持著「輸出即是成長」的理念,這些文章是過去慢慢累積的我、也是未來前進的動力,希望未來仍然可以持續成長與進步,明年再來分享其他主題!