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 指向不對。
總結
- 基本功:參數和回傳值都要標型別。
- 彈性:善用
?(可選) 和=(預設值)。 - 動態:遇到「多種輸入對應多種輸出」的複雜情況,使用重載 (Overloads)。