閱讀今天的文章前,先回顧一下昨天的學習,回答看看:
- 函式在 TypeScript 的型別推論和型別註記機制為何?
- 若參數推論為 any 型別,TS 會如何進行編譯呢?
如果有點不清楚答案的話,可以看看 Day08 的文章喔!
今天要來討論幾種 TS 函式的機制與常見情境:
倘若函式沒有回傳值,回傳值的型別會是什麼呢?
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.
預設參數和可選參數都有個共同點,那就是參數的數量明確。但如果想同時操作多個參數,但又不知道會有多少參數會傳進來,要怎麼做呢?
在 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 中,剩餘參數會被當作個數不限的可選參數,可以一個都沒有,也可以有無數個。
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)等,明天將探討新的陣列型別,那我們明天見!
如有錯誤的地方,還請留言告知,我會盡快修改調整,感謝:)