Skip to main content

[TS] TypeScript Function Type

函式參數#

當一個函式被建立但沒有對其參數進行型別註記時,預設會被套用 any這是不建議的寫法

使用 Type Alias 定義函式型別#

type Greet = (name: string, age: number) => string;
const greet: Greet = (name, age) => {
return `Hello ${name}, your age is ${age}.`;
};
console.log(greet('Aaron', 30));

使用箭頭函式#

/* 使用箭頭函式 */
const add = (a: number, b: number): number => a + b;
const sendTextMessage = (
to: HasPhoneNumber
): { recipient: string; body: string } => {
return {
recipient: `${to.name} <${to.phone}>`, // Aaron <0912345678>
body: "You're pre-qualified for a loan",
};
};
// 等同於,在變數後直接註記型別為函式
// (a: number, b: number) => number 是 type
const add: (a: number, b: number) => number = (a, b) => a + b;

使用 function 語法#

使用 function 關鍵字來建立函式:

// function statement
function add(x: number, y: number): number {
return x + y;
}
function sendEmail(to: HasEmail): { recipient: string; body: string } {
return {
recipient: `${to.name} <${to.email}>`, // Aaron <pjchender@gmail.com>
body: "You're pre-qualified for a loan",
};
}
// function expression
const add = function (a: number, b: number): number {
return a + b;
};
const sendEmail = function (to: HasEmail): {
recipient: string;
body: string;
} {
return {
recipient: `${to.name} <${to.email}>`, // Aaron <pjchender@gmail.com>
body: "You're pre-qualified for a loan",
};
};

參數中解構賦值#

const greet = ({ firstName, lastName }: { firstName: string; lastName: string }): void => {
console.log(`Hello ${lastName} ${firstName}`);
};

選填性的參數與參數預設值#

Optional and Default Parameters @ TypeScript Docs

選填性參數(optional parameters)#

雖然在 JavaScript 中沒有被帶入的函式參數會是 undefined 且可以正常運作,但在 TypeScript 中,函式的參數預設都是必填的,沒填的話 compiler 會直接噴錯。

若有函式的參數需要是選填的,可以在參數後面使用 ?,例如:

// firstName 是必填,lastName 則可以選填
const getName = (firstName: string, lastName?: string) =>
lastName ? `${firstName} ${lastName}` : firstName;
caution

optional parameter 一定只能放在 required parameter 的後面。

使用參數預設值(default-initialized parameters)#

除了函式的參數可以選填之外,同樣可以使用參數的預設值:

const getName = (firstName: string, lastName = 'Chen') => `${firstName} ${lastName}`;
getName('Aaron');

此時 lastName 的 type 一樣會是 lastName?: string,因此當函式的參數 lastName 沒有給值時,會自動使用 Aaron

然而,和一般的 optional parameters 不同,default-initialized parameters 不一定只能放在 required parameters 的後面,但如果放在前面的話,在呼叫該函式的時候要使用 undefined。例如:

const getName = (firstName = 'Aaron', lastName: string) => `${firstName} ${lastName}`;
// 當 default parameters 在 required parameters 前,使用時需要帶入 undefined
getName(undefined, 'Chen');

Rest Parameters#

Rest Parameters @ TypeScript Docs

在 TypeScript 中一樣可以使用 rest parameters:

// example 1
const getName = (firstName: string, ...rest: string[]) => `${firstName} ${rest.join(' ')}`;
const name = getName('PJ', 'Aaron', 'Chen');
// example 2
const sum = (...values: number[]) =>
values.reduce((accumulate, current) => accumulate + current, 0);
const total = sum(1, 2, 3, 4);

Function Overload(函式超載)#

函式超載指的是擴充一個函式可以被執行的形式(例如,介面)。舉例來說,在實作函式(function implementation)時,提供了一個比較廣泛的型別,

/**
* Provide multiple function signatures (overload signatures)
*/
// "overload signatures"
function contactPeople(method: 'email', ...people: HasEmail[]): void;
function contactPeople(method: 'phone', ...people: HasPhoneNumber[]): void;
// "function implementation": 需要同時符合 overload signatures 的情況
// 期望 method 是 emails 時,...people 的型別是 HasEmail[]
// 而 method 是 phone 時,...people 的型別是 HasPhoneNumber[]
// 這時可以在函式的上方撰寫 overload signatures
function contactPeople(
method: 'email' | 'phone',
...people: (HasEmail | HasPhoneNumber)[]
) {
if (method === 'email') {
(people as HasEmail[]).forEach(sendEmail);
} else if (method === 'phone') {
(people as HasPhoneNumber[]).forEach(sendTextMessage);
}
}
contactPeople('email', { name: 'Aaron', email: 'pjchender@gmail.com' });
// 如果沒有使用 overload signature 的話,下面這行的用法 TS 不會報錯,但與我們的預期不同
// 因為我們希望 method 是 'phone' 時,後面物件的型別要是 HasPhoneNumber
contactPeople('phone', { name: 'Aaron', email: 'pjchender@gmail.com' }); // 在使用了 function overload 之後,TS 會報錯誤

成功使用 function overload 之後,VSCode 的 parameter hints 會跳出提示來說明可用的 function signatures:

function overload

Last updated on