iT邦幫忙

2024 iThome 鐵人賽

DAY 10
0
JavaScript

我推的TypeScript 操作大全系列 第 10

我推Day10 - TypeScript 函數多載 Function Overloading 的神奇力量!

  • 分享至 

  • xImage
  •  

https://ithelp.ithome.com.tw/upload/images/20240924/20124462icBFyTHsnc.jpg

生活化的 TypeScript 函式多載 ( Function Overloading )應用場景

要理解 TypeScript 函式多載的概念,可以把它想像成生活中我們常見的「同一種行為有多種執行方式」的情境。
以下是一些日常例子,幫助你更直觀地理解這個技術:

  1. 點餐系統的應用

    • 想像你在餐廳點餐,有多種點餐方式:你可以直接告訴服務員你的選擇(語音點餐),也可以用平板選菜(點擊操作),還可以寫在紙上交給他(紙上點餐)。這些方式都可以達到同樣的目的:點餐。
    • 在程式碼中,這相當於同一個 order 函數有多種不同的參數組合和調用方式,這些多載的簽名就像不同的點餐方式,最終都是為了完成點餐這個任務。
    function order(dish: string): void // 口頭點餐
    function order(dish: string, extras: string[]): void // 加點配料
    function order(dish: string, callback: (confirmation: string) => void): void // 使用回呼函數
    
  2. 搜尋產品

    • 假設你在網路商城上搜尋商品,有多種搜尋方式:你可以只輸入關鍵字(例如「筆電」),也可以進一步加入篩選條件(例如價格、品牌),還可以設置通知功能(例如搜尋後自動提醒你有折扣)。
    • 在這裡,search 函數的多載簽名像是給搜尋行為添加不同的功能層次。
    function search(term: string): Promise<Product[]> // 簡單搜尋
    function search(term: string, filters: string[]): Promise<Product[]> // 帶篩選條件
    function search(term: string, callback: (products: Product[]) => void, filters?: string[]): void // 搜尋結果後觸發通知
    
  3. 約會提醒

    • 假設你要提醒朋友聚會,有多種提醒方式:直接發訊息告知、設定日曆提醒,或者寄電子郵件,這些都是提醒的不同方法。
    • 在程式碼中,這種場景對應到函式多載,就是同一個 remind 函數可以根據不同參數組合以不同方式執行提醒。
    function remind(person: string, method: "message"): void // 發訊息
    function remind(person: string, method: "calendar"): void // 日曆提醒
    function remind(person: string, method: "email"): void // 寄電子郵件
    

**函式多載 Function Overloading ** 的核心是:同一個行為或操作,根據情況使用不同的「方式」來實現,讓程式碼變得靈活且符合實際需求。


理解 TypeScript 的函式多載

在 TypeScript 中,函式多載 (Function Overloading) 允許為函數定義多個簽名(signatures),每個簽名可以有不同的參數類型和返回類型。這在需要提供多種方式調用函數的情況下非常實用,同時還能保持類型安全。以下,我們將透過一個實際的例子探討函式多載的使用。

程式碼範例解析

在以下程式碼中,我們有一個 search 函數,具有三個不同的多載簽名:

type Result = {
  title: string,
  url: string,
  abstract: string
}

// 第一個多載:返回 Result 陣列的 Promise
function search(
  term: string,
  tags?: string[]
): Promise<Result[]>

// 第二個多載:接受回呼函數並返回 void
function search(
  term: string,
  callback: (results: Result[]) => void,
  tags?: string[]
): void

// 實際實現,包含所有可能的參數組合
function search(
  term: string,
  p2?: string[] | ((results: Result[]) => void),
  p3?: string[]
) {
  // 判斷 p2 是否為回呼函數
  const callback = 
    typeof p2 === 'function' ? p2 : undefined

  // 判斷是否提供了 tags
  const tags = 
    typeof p2 !== 'undefined' && Array.isArray(p2) ? p2 :
    typeof p3 !== 'undefined' && Array.isArray(p3) ? p3 : 
    undefined;
 
  let queryString = `?query=${term}`

  if (tags && tags.length) {
    queryString += `&tags=${tags.join()}`
  }

  // 向伺服器請求搜尋結果
  const results = fetch(`/search${queryString}`)
    .then(response => response.json())

  // 如果有提供回呼函數則使用它,否則返回 Promise
  if (callback) {
    results.then(res => callback(res))
    return
  } else {
    return results
  }
}

程式碼如何運作

  1. 函數簽名與載

    • 第一個簽名允許使用搜尋詞和可選的 tags 呼叫 search,並返回解析為 Result 陣列的 Promise
    • 第二個簽名允許使用搜尋詞、回呼函數和可選的 tags 呼叫 search,不返回任何值,而是直接透過回呼處理搜尋結果。
  2. 實現細節

    • 第三個實現將兩個簽名的參數結合到一個靈活的函數中,使用類型守衛(type guards)來區分第二個參數 (p2) 是回呼函數還是 tags 陣列。
    • 如果 p2 是函數,則將其視為回呼;如果 p2p3 是陣列,則視為 tags。
  3. 根據參數執行不同邏輯

    • 如果提供了回呼函數,search 將獲取結果並將其傳遞給回呼函數,而不返回任何東西,符合第二個多載的 void 返回類型。
    • 如果沒有提供回呼函數,則返回結果的 Promise,符合第一個多載的 Promise<Result[]> 返回類型。

函式多載的優點

  • 清晰與靈活:透過定義不同的函數調用方式,使開發人員更容易理解如何使用函數。
  • 類型安全:每個多載簽名明確地定義了函數所期望的參數和返回結果,使程式碼更易於理解且更不容易出錯。
  • 避免手動類型檢查:透過 TypeScript 的類型系統,減少了在函數內部進行手動類型檢查的需求,簡化了實現。

使用範例

  1. 返回 Promise

    search("TypeScript", ["programming", "language"])
      .then(results => {
        console.log(results);
      });
    
  2. 使用回呼函數

    search("TypeScript", (results) => {
      console.log(results);
    }, ["programming", "language"]);
    

在這些範例中,你可以看到函式多載如何提供兩種不同的方式來使用 search 函數,取決於所需的行為。


正確姿勢使用 TypeScript 函式多載

TypeScript 的函式多載是程式碼世界的萬能膠!要發揮它的最大威力,以下幾點正確姿勢你一定要知道:

  1. 精準定義多載簽名:每個多載簽名都應該清楚地反映出不同的使用情境,避免讓人搞不清楚該用哪種方式調用函數。

  2. 避免濫用:雖然多載超好用,但也別為了多載而多載,確保每個多載都是真正需要的,避免讓程式碼變成難以維護的怪獸。

  3. 保持一致性:實現的函數體要能支持所有多載簽名,確保每種調用方式都能正常運行,不然會掉入意料之外的坑裡!

  4. 善用類型守衛:透過 TypeScript 的類型守衛來區分不同的參數組合,讓你的多載實現更清晰、更穩定。

  5. 加強可讀性與維護性:多載的目的是讓程式碼易讀、好維護,不要把邏輯寫得過於複雜,記住我們的目標是清楚簡潔!

正確使用 TypeScript 函式多載,可以讓你的程式碼靈活應對不同的需求,寫得更漂亮、更專業。
像我們的 search 函數一樣,輕鬆面對各種參數組合,實現更豐富的功能吧!٩(^ᴗ^)۶


上一篇
我推Day09 - 用 TypeScript 型別守護我們的技術派對!
下一篇
我推Day11 - TypeScript 除錯大法!破解隱藏錯誤,讓你寫出零Bug神級程式
系列文
我推的TypeScript 操作大全30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言