TypeScript 函式 (Function)

函式是我們寫程式最常用的工具。在 JavaScript 中,我們常常會遇到「傳錯參數」或「回傳值不如預期」的問題,而 TypeScript 可以幫我們解決這一切。

簡單來說,TypeScript 的函式只多了兩件事:規定輸入 (參數型別)規定輸出 (回傳型別)

基本宣告

參數與回傳值

// (a: number, b: number) -> 規定輸入必須是 number
// : number -> 規定輸出一定是 number
function add(a: number, b: number): number {
  return a + b;
}

// 呼叫時會自動檢查
add(1, 2); // OK
// add("1", 2); // 錯誤:參數型別不對

箭頭函式 (Arrow Functions)

語法也是一樣的,只是型別註解寫在括號內。

const multiply = (a: number, b: number): number => {
  return a * b;
};

// 簡寫形式
const subtract = (a: number, b: number): number => a - b;

參數的各種型態

1. 可選參數 (Optional)

有時候我們不確定使用者會不會傳某個參數,這時可以用 ?

// lastName? 表示這個參數可有可無
function buildName(firstName: string, lastName?: string) {
  if (lastName) {
    return `${firstName} ${lastName}`;
  }
  return firstName;
}

buildName('Bob'); // OK,回傳 "Bob"
buildName('Bob', 'Adams'); // OK,回傳 "Bob Adams"

注意:可選參數 (?) 必須放在所有必填參數的後面

2. 預設參數 (Default)

如果你想給參數一個預設值,直接用 = 即可。TS 會自動推論它是可選的,且型別會對應到預設值的型別。

// 如果沒傳 greeting,預設就是 "Hello"
function greet(name: string, greeting = 'Hello') {
  return `${greeting}, ${name}`;
}

greet('Bob'); // "Hello, Bob"
greet('Bob', 'Hi'); // "Hi, Bob"

3. 其餘參數 (Rest Parameters)

當你不確定會傳入多少個參數時 (例如 Math.max),可以用 ... 語法,把參數收集成一個陣列。

// ...nums: number[] 表示可以接收任意數量的 number
function sum(...nums: number[]): number {
  return nums.reduce((total, n) => total + n, 0);
}

sum(1, 2); // 3
sum(1, 2, 3); // 6

函式重載 (Function Overloads)

這是 TypeScript 一個比較進階但實用的功能。

有些 JavaScript 函式非常靈活,例如傳入字串時回傳數字,傳入數字時回傳陣列。為了準確描述這種「輸入 A -> 輸出 A,輸入 B -> 輸出 B」的對應關係,我們需要使用重載

寫法是:先寫好幾個「簽名 (Signature)」,最後再寫一個「實作 (Implementation)」。

// 簽名 1:傳字串,回傳字串陣列
function makeArray(input: string): string[];
// 簽名 2:傳數字,回傳數字陣列
function makeArray(input: number): number[];

// 實作 (Implementation):這裡要處理所有可能的情況
// 注意:這個實作的簽名對外是隱藏的,使用者只會看到上面兩個簽名
function makeArray(input: string | number): string[] | number[] {
  if (typeof input === 'string') {
    return input.split('');
  } else {
    return [input];
  }
}

const strArr = makeArray('abc'); // 自動推論為 string[]
const numArr = makeArray(123); // 自動推論為 number[]

關於 this

在 JavaScript 中,this 的指向常常讓人頭痛。TypeScript 允許你this 當成函式的第一個假參數來標註它的型別。

interface User {
  id: number;
  admin: boolean;
  becomeAdmin: () => void;
}

const user = {
  id: 123,
  admin: false,
  // 顯式宣告 this 必須是 User 型別
  becomeAdmin(this: User) {
    this.admin = true;
  },
};

這樣當你在錯誤的上下文呼叫 becomeAdmin 時,TS 就會警告你 this 指向不對。

總結

  1. 基本功:參數和回傳值都要標型別。
  2. 彈性:善用 ? (可選) 和 = (預設值)。
  3. 動態:遇到「多種輸入對應多種輸出」的複雜情況,使用重載 (Overloads)