iT邦幫忙

第 11 屆 iT 邦幫忙鐵人賽

DAY 9
1
自我挑戰組

Typescript 初心者手札系列 第 9

【Day 09】TypeScript 資料型別 - 函式型別(Function Types)-(下)

閱讀今天的文章前,先回顧一下昨天的學習,回答看看:

  • 函式在 TypeScript 的型別推論和型別註記機制為何?
  • 若參數推論為 any 型別,TS 會如何進行編譯呢?

如果有點不清楚答案的話,可以看看 Day08 的文章喔!

今天要來討論幾種 TS 函式的機制與常見情境:

函式沒有回傳值:void

倘若函式沒有回傳值,回傳值的型別會是什麼呢?

function add(x: number, y: number) {
  console.log(x + y)
}

把滑鼠指標放在 add 上方,這時候出現了一個我們還沒介紹到的型別 void

在 JS 中没有空值(void)的概念,如果函式沒有回傳,就會自動回傳 undefined,但在 TS 中,可以用 void 表示没有任何回傳值的函式。

那如果在 TS 中設定回傳值為 undefined,TS 會如何推斷函式回傳型別呢?又如果註記回傳值為 undefined 或 void 又會發生什麼事呢?

讓我們把幾種可能的情境都測試看看吧!

//1. 函式沒有回傳值 => 回傳值推論為void,PASS!
function add(x: number, y: number) {
  console.log(x + y)
}

//2. 函式回傳undefined => 回傳值推論為undefined,PASS!
function add1(x: number, y: number) {
  return undefined
}

//3. 函式回傳值註記型別為 undefined,回傳 undefined => 回傳值型別為undefined,PASS!
function add2(x: number, y: number):undefined {
  return undefined
}

//4. 函式回傳值註記型別為 undefined,但函式沒有回傳值 => 報錯
function add3(x: number, y: number):undefined {
   console.log(x+y)
}

//5. 函式回傳值註記型別為 undefined,但函式內容為空 => 報錯
function add3(x: number, y: number):undefined {
   
}

//6. 函式回傳值註記為 void,但函式回傳 undefined => PASS!
function add4(x: number, y: number):void {
  return undefined
}

//7. 函式回傳值註記為 void,但函式沒有回傳值 => PASS!
function add5(x: number, y: number):void {
  console.log(x + y)
}

由上面的測試,我們可以推論當函式回傳值註記為 undefined 時,函式一定要回傳 undefined 才行(因為 undefined 屬於 undefined 型別,一定要回傳符合的型別),如此,上面的 4、5都會報錯。但是若回傳值註記為 void 時,沒有回傳值或是回傳值為 undefined 都是可以被 TS 接受的。

函式可選參數和預設參數

昨天我們有探討到傳遞給函式的參數個數必須和函式期望的一樣,我們知道當函式傳入多餘(或者少於)的參數時 TS 都會報錯!但這不代表不能傳遞 null 或 undefinned 作為參數,而是說編譯器會檢查是否每個參數都有傳值。

但是,其實 TS 中加入了可選參數的機制,只要在參數名稱後方加上問號(?)即可使參數成為可選參數。

function foo(bar: number, bas?: string): void {
    console.log(bar, bas)
}

foo(123); //(123, undefined)
foo(123, 'hello'); //(123, "hello")
foo(123, 'hello','world') // Error : Expected 1-2 arguments, but got 3
foo() // Error: Expected 1-2 arguments, but got 0

這時候,bas 參數可有可無,就算沒有傳入,TS也不會報錯,但如果參數傳多或傳少了,仍然會報錯。

另外,在 ES6 中,函式可以設定預設參數值,在 TS 中同樣支援,可以在參數型別後使用 = 表示

function foo(bar: number, bas: string = 'hello') {
    console.log(bar, bas);
}

foo(123);           // 123 "hello"
foo(123, 'world');  // 123 "world"

但在使用可選參數時,要注意擺放的位置,可選參數後面不允許必要參數,預設參數則沒有限制。

//可選參數後面不允許必要參數,報錯
function foo(bar?: number, bas: string): void {
    console.log(bar, bas)
}
//Error: A required parameter cannot follow an optional parameter.

剩餘參數(rest parameters)

預設參數和可選參數都有個共同點,那就是參數的數量明確。但如果想同時操作多個參數,但又不知道會有多少參數會傳進來,要怎麼做呢?

在 ES6 中出現了剩餘參數(rest parameter) 語法,可以把函式最後一個命名參數以...開頭,將後面不確定數量的參數視為一個陣列

function buildName(firstName: string, ...restOfName: string[]) {
  return firstName + " " + restOfName.join(" ");
}

let a = buildName("Joseph", "Samuel", "Lucas", "MacKinzie") 
console.log(a) //Joseph Samuel Lucas MacKinzie

在 TS 中,剩餘參數會被當作個數不限的可選參數,可以一個都沒有,也可以有無數個。

重載(overloads)

TS 允許我們定義一個函式接受不同數量或類型的參數,編譯器會根據其型別定義處理函式的調用,例如:我們需要有一個函式 add,輸入數字 1 和 2 時,回傳相加總和3,而輸入字串'hello'和'Kira'時,回傳相連字串'hello Kira'。

為了能夠精確地表達,輸入是數字時,輸出也應該是數字; 而輸入是字串時,輸出也應該是字串,這時候就可以使用重載定義多個 add 函式

function add(a:string, b:string):string;
function add(a:number, b:number): number;
function add(a: any, b:any): any {
    return a + b;
}

add("hello ", "Kira"); // "hello Kira" 
add(1, 2); //  3 

上面的範例中,我們重複定義了兩個重載,一個回傳字串,一個回傳數字,最後一個函式定義執行程式碼。TS 會遵循與 JS 相似的過程,會從由上往下逐一進行匹配,直到找到一個完全匹配的函式,否則報錯。官方推薦的做法是將更精確定義的重載放在上面,不具體的放下面。

小結

今天延伸討論了 TS 中函式的特殊機制和情境,包括:函式沒有回傳值、可選和預設參數的使用、剩餘參數及重載(overloads)等,明天將探討新的陣列型別,那我們明天見!

如有錯誤的地方,還請留言告知,我會盡快修改調整,感謝:)


上一篇
【Day 08】TypeScript 資料型別 - 函式型別(Function Types)-(上)
下一篇
【Day 10】TypeScript 資料型別 - 陣列型別(Array Types)-(上)
系列文
Typescript 初心者手札30

尚未有邦友留言

立即登入留言