iT邦幫忙

2024 iThome 鐵人賽

DAY 30
0
JavaScript

用 TypeScript 重新定義前端開發:30 天的實踐與思考系列 第 30

Day30:TypeScript 在大型應用中的應用淺談

  • 分享至 

  • xImage
  •  

隨著前端技術的不斷發展,現代應用變得愈來愈複雜,開發團隊也愈來愈龐大。這時候,強大的型別系統與模組化結構就顯得至關重要。而 TypeScript,作為 JavaScript 的型別超集,不僅解決了這些挑戰,還提供了工具來提升程式碼的可維護性、可擴展性以及可讀性。

一、大型應用中的挑戰

當應用程式逐漸變大,你可能會遇到以下問題:

  • 程式碼可讀性下降:隨著功能增多,邏輯會變得更加複雜,讓人難以理解。
  • 易於出錯:稍微修改某處程式碼,可能會意外影響到其它部分的運行。
  • 重複程式碼:在不同地方撰寫相似的程式碼,導致維護困難。
  • 溝通成本增高:當團隊擴大時,不同開發者對同一段程式碼的理解可能不同,增加了溝通成本。

二、TypeScript 解決之道

1. 模組化

模組化是解決大型應用可維護性問題的核心手段。透過模組化,我們可以將程式碼拆分成獨立的部分,每一部分負責一個特定的功能。

透過模組化,我們可以:

  • 提高可重用性:每個模組只負責一件事,這讓它們能夠在不同的場景下被重複使用。
  • 易於測試:小型模組的邏輯相對簡單,讓單元測試變得更加直觀。

(1) 目錄結構應用範例:

模組化的好處在於它將不同的業務邏輯分開,使團隊可以並行開發不同模組,減少彼此間的依賴,提升維護和擴展性。

  • 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

(2) 程式碼範例:

假設團隊正在開發一個電商平台,其中的購物車功能需要管理商品的增減、總價或折扣後金額計算等邏輯。傳統的做法可能會把這些邏輯都寫在一個大文件中,但這不僅難以維護,也容易出錯。而通過模組化,就可以將不同的功能拆分到不同的模組中。

// 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 類中,並且可以在其它地方重複使用這個模組。

2. 封裝與復用

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,這樣外部無法直接訪問或修改內部狀態。

3. 型別管理

在大型應用中,型別管理的作用不容忽視。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 傳給電子商品類型的產品。

4. 模組與型別結合

當應用程式越來越大時,模組與型別的結合就顯得尤為重要。透過將每個模組的邏輯封裝起來,並對外部提供清晰的型別定義,可以大大提高程式碼的可維護性與易讀性。

範例:

在電商平台的購物車中,我們可以這樣結合模組與型別:

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 的主題,但是秉持著「輸出即是成長」的理念,這些文章是過去慢慢累積的我、也是未來前進的動力,希望未來仍然可以持續成長與進步,明年再來分享其他主題!


上一篇
Day29:使用 TypeScript 寫測試 - Jest 篇
系列文
用 TypeScript 重新定義前端開發:30 天的實踐與思考30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言