iT邦幫忙

2025 iThome 鐵人賽

DAY 10
0
Modern Web

我與型別的 30 天約定:TypeScript 入坑實錄系列 第 10

Day 10|函式型別:參數、回傳值全都要規範起來

  • 分享至 

  • xImage
  •  

今天要進入 TypeScript 型別系統中另一個很重要的領域——函式型別

在 JS 裡,函式的參數型別、回傳值完全靠人自律;

在 TS 裡,我們可以用型別把它們鎖得死死的,少打很多莫名其妙的 bug。


1. 基本函式型別定義

方式 1:直接註記參數與回傳型別

function add(a: number, b: number): number {
  return a + b;
}
  • a: number, b: number → 限制參數型別
  • : number → 限制回傳值型別

方式 2:用型別別名

type AddFn = (a: number, b: number) => number;

const add: AddFn = (x, y) => x + y;

好處是可以重複使用型別,尤其適合多個函式簽名一致的情況。


方式 3:用 Interface(專門定義物件方法時常用)

interface AddFn {
  (a: number, b: number): number;
}

const add: AddFn = (x, y) => x + y;

2. 可選參數(Optional Parameter)

? 表示該參數可選:

function greet(name: string, title?: string) {
  if (title) {
    console.log(`${title} ${name}`);
  } else {
    console.log(name);
  }
}

greet("Marco");
greet("Marco", "Dr.");

3. 預設參數

function greet(name: string, title: string = "Mr./Ms.") {
  console.log(`${title} ${name}`);
}

4. 剩餘參數(Rest Parameter)

接收不定數量參數:

function sum(...numbers: number[]): number {
  return numbers.reduce((acc, cur) => acc + cur, 0);
}

console.log(sum(1, 2, 3, 4)); // 10

5. 函式重載(Overloading)

允許同一個函式有多種型別簽名:

function getValue(x: string): string;
function getValue(x: number): number;
function getValue(x: string | number): string | number {
  return x;
}

let a = getValue("abc"); // 推論成 string
let b = getValue(123);   // 推論成 number

注意:最後的實作必須能處理所有簽名的情況。


6. 實務案例:API 呼叫封裝

type HttpMethod = "GET" | "POST";

function request(url: string, method: HttpMethod, body?: any): Promise<any> {
  return fetch(url, {
    method,
    body: body ? JSON.stringify(body) : undefined
  }).then(res => res.json());
}

request("/api/users", "GET");
request("/api/users", "POST", { name: "Alice" });

7. 常見踩坑

7.1 參數比定義多

TS 允許多傳參數,但會忽略多餘的:

function log(msg: string) {
  console.log(msg);
}

log("Hello", "World"); // 第二個參數被忽略

建議:多參數情況要明確定義剩餘參數。


7.2 回傳型別推論 vs 明確定義

有時候推論就好,但在公共 API上要明確定義回傳型別,避免日後修改造成型別變動。


8. 搭配泛型的函式型別(預告)

函式型別遇上泛型會更強大:

function identity<T>(value: T): T {
  return value;
}

let num = identity(123);     // T = number
let str = identity("Hello"); // T = string

泛型函式會在 Day 11 詳解。


上一篇
Day 9|Type Alias vs Interface:雙雄對決,該選誰?
下一篇
Day 11|泛型 Generics:讓型別變得聰明又彈性
系列文
我與型別的 30 天約定:TypeScript 入坑實錄12
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言