Day 13 終於來到函式(function),函式篇章也不會太難,只是有一些觀念要留意。
在TypeScript裡,要替函式加上型別的語法如下:
function name(para1: type, para2: type): returnType{
// ...
}
事實上,TypeScript compiler也能自行推導函式回傳值型別,例如以下函式:
function sum(num1: number, num2:number) {
returm num1 + num2;
}
在這個比較簡單的加總函式裡,回傳值型別會自動被推導成 number
型別。不過要注意的是,如果回傳型別比較複雜,可能是好幾個型別合併的型別,回傳型別就有可能被推倒成 Union
或 any
。如果想避免被推導成 any
型別,建議還是明確寫出回傳值的型別。
另外之前在講TypeScript基本型別有一個是 void
,也就是明確指明函式沒有回傳值或回傳 undefined
:
function pring(message: string): void {
console.log(message);
}
如果函式有參數(parameter),則TypeScript會檢查使用函式所代入的引數(argument)數量和型別是否符合所定義函式的參數數量和型別:
function sum (num1: number, num2: number, num3: number): number {
return num1 + num2 + num3;
}
console.log(sum(1, 2)); // error
如果想解決部分參數其實是非必要參數的問題,就可以使用optional parameter(中文不確定怎麼解釋)。如同前幾篇所說,只要提到 optional 就會想到要用的符號就是 ?
:
function sum (num1: number, num2: number, num3?: number): number {
if(typeof num3 !== 'undefined'){
return num1 + num2 + num3;
}
return num1 + num2;
}
sum(1, 2); // 3
這裡唯一要留意的是,如果參數是optional parameter,則必須放在不是optional parameters的參數後面。
optional parameter第一個範例因為沒有指定optional parameter所以出現了錯誤,而這樣的錯誤其實也可以用預設參數(default parameter)去避免:
function sum (num1: number, num2: number, num3: number = 0): number {
return num1 + num2 + num3;
}
console.log(sum(1, 2)); // 3
在這個範例裡,因為第三個參數有給定預設值為0,所以在使用 sum(1, 2)
呼叫函式時,回傳的東西就相當於 return 1 + 2 + 0;
。
不過和 optional parameter 不同的是:
undefined
當作預設參數的引數。第2個要點的意思如下:
function sum (num1: number = 0, num2: number, num3: number): number {
return num1 + num2 + num3; // 等價於 0 + 1 + 2
}
console.log(sum(1, 2)); // 3
有時候我們不確定要輸入的參數數量,這時可以使用不定參數(rest parameters),跟JavaScript一樣,一個函式只能有一個不定參數並且必須是最後一個參數。若要在TypeScript使用不訂參數,可以指定不定參數的型別為陣列:
function sum (...rest: number[]): number {
let sum = 0;
rest.forEach(num => sum+= num);
return sum;
}
console.log(sum(1, 2, 3, 4, 5)); // 15
JavaScript本身是沒有Overloads的概念,如果有兩個同名函式,由上往下依序讀取JavaScript檔案的話,下面的函式會覆蓋掉上面寫的函式。
但在TypeScript語法裡,我們可以寫出類似其他語言的Overloading functions,不過TypeScript的overloads和其他語言的overloads概念是不同的。
TypeScript的overloads主要是為了建立函式參數型別和回傳值型別之間的關聯,這邊使用TypeScript Tutorial的overloads舉例:
// TypeScript
function add(input1: number | string, input2: number | string): number | string {
if(typeof input1 === 'number' && typeof input2 === 'number'){
return input1 + input2;
}
if(typeof input1 === 'string' && typeof input2 === 'string'){
return input1 + input2;
}
}
我們知道兩個 number
型的數值可以用 +
相加;兩個 string
型的值可以用 +
串接,但即使加入判斷參數型別的程式碼,其實也無法保證回傳值的型別是 number
還是 string
,這個時候就能用TypeScript的overloading function語法:
function add(input1: number, input2: number): number;
function add(input1: string, input2: string): string;
function add(input1: any, input2: any): any {
return input1 + input2;
}
從這邊就可以看出不同型別的輸入參數都有相同型別的回傳值,只是使用overloading function要有相同數量的參數,否則就要使用optional parameter:
function add(input1: number, input2: number): number;
function add(input1: string, input2: string): string;
function add(input1: number, input2: number, input3?: number): number{
if(input3){
return input1 + input2 + input3;
}
return input1 + input2;
}
此外,class語法裡的function,即method,也支援overloading function,若有需要就可以將method寫成overloads的形式。
今天function的淺談就到這裡,明天開始會認識比較重要的語法,像是 class
、interface
、generic
等,若有時間也會加入怎麼在React裡用TypeScript。
參考資料
TypeScript Tutorial
TypeScript for JavaScript Programmers
Function Overloading in JavaScript