TypeScript/ES6 對 function 支援的擴展

TypeScript 的 function 可對參數做強型別檢查與 function type,此外 ES6 還多了 optional / default / rest parameter,當然 TypeScript 也可使用。

Version


TypeScript 2.3

Parameter with Type


1
2
3
4
5
6
7
// named function
function add(x: number, y: number): number {
return x + y;
}

// anonymous function
let myAdd = function(x: number, y: number): number { return x+y; };

無論是 named function 或者是 anonymous function,都可以在參數與回傳值明確指定 type,讓編譯器幫我們做檢查,一但型別錯誤,編譯將會失敗。

Function Type


除了參數加上型別外,我們還可以對整個 function 也加上型別,讓編譯器幫我們檢查 function 是否符合這個型別。

1
2
let myAdd: (x: number, y: number)=>number =
function(x: number, y: number): number { return x+y; };

myAdd 的型別為 (x: number, y: number)=>number,關於 function type,主要分成兩部分:

  • 參數型別
  • 回傳值型別

因為宣告了 function type,在 = 之後的 anonymous function 就必須符合所規定的 function type,若 anonymous function 不符合 function type,編譯會錯誤。

不過在實務上,我們不會真的這樣寫,因為實在太冗長了,只會寫成:

1
let myAdd = function(x: number, y: number): number { return x+y; };

TypeScript 編譯器會自動幫我們轉成

1
2
let myAdd: (x: number, y: number)=>number =
function(x: number, y: number): number { return x+y; };

TypeScript 會自動幫我們將 myAdd 加上型別,若之後再指定其他 function 給 myAdd,只要不符合 function type 就會報錯。

TypeScript 在觀念上有 function type,不過實務上不用特別去指定 function type,只要將 anonymous function 指定給變數,就會自動幫我們加上 function type。

Optional Parameters


1
2
3
4
5
6
7
function buildName(firstName: string, lastName: string) {
return firstName + " " + lastName;
}

let result1 = buildName("Bob"); // 編譯錯誤,少 1 個參數
let result2 = buildName("Bob", "Adams", "Sr."); // 編譯錯誤,多 1 個參數
let result3 = buildName("Bob", "Adams"); // 編譯通過

在 TypeScript 世界,既然宣告了參數,就代表傳入參數的個數與型別必須完全符合,過多或過少都不行。

但 JavaScript 世界,每個變數都是 optional,若參數個數不對,只是 undefined 而已,為了讓 TypeScript 有強型別檢查,又能相容於 JavaScript 習慣,可在參數後加上 ?

1
2
3
4
5
6
7
8
9
10
function buildName(firstName: string, lastName?: string) {
if (lastName)
return firstName + " " + lastName;
else
return firstName;
}

let result1 = buildName("Bob"); // 編譯通過
let result2 = buildName("Bob", "Adams", "Sr."); // 編譯錯誤,多一個
let result3 = buildName("Bob", "Adams"); // 編譯通過

若使用 ? optional parameter,記得將必要參數寫在最前面,後面才擺 optional parameter。

Default Parameter


1
2
3
4
5
6
7
8
function buildName(firstName: string, lastName = "Smith") {
return firstName + " " + lastName;
}

let result1 = buildName("Bob"); // Bob Smith
let result2 = buildName("Bob", undefined); // Bob Smite
let result3 = buildName("Bob", "Adams", "Sr."); // 編譯錯誤,多一個參數
let result4 = buildName("Bob", "Adams"); // Bob Adams

TypeScript 亦提供 default parameter,當傳入 undefined 時,則會以 default parameter 取代。

Default parameter 若放在必要參數後面,則相當於 optional parameter 一樣,只是差別在有預設值。

Default parameter 並不像 optional parameter 一樣,一定放在必要參數後面,若放在必要參數前面,則必須明確的指定 undefined,而不能省略。

Rest Parameter


1
2
3
4
5
6
function buildName(firstName: string, ...restOfName: string[]) {
return firstName + " " + restOfName.join(" ");
}

let employeeName = buildName("Kevin", "Jeff", "Jimmy");
console.log(employeeName); // Kevin Jeff Jimmy

無論是 optional parameter,或是 default paramter,討論的都是一個參數對應一個值,但實務上可能遇到參數個數不確定,希望參數以陣列接收。

第 1 行

1
...restOfName: string[]

宣告為 rest parameter,並明確宣告其型別為 string 陣列,則無論多少參數個數,最後都會塞進 restOfName 陣列。

Conclusion


  • Function 的參數加上型別檢查後,我們將可少撰寫很多檢查型別的程式碼,由 TypeScript 編譯器幫我們把關。
  • 有了 optioanl / default / rest parameter,參數將更加靈活。

References


TypeScript, Handbook : Functions

2017-06-17