函數是 JavaScript 中的一等公民
函數聲明
在 JavaScript 中,有兩種常見的定義函數的方式——函數聲明(Function Declaration)和函數表達式(Function Expression).
一個函數有輸入和輸出,要在 TypeScript 中對其進行約束,需要把輸入和輸出都考慮到,其中函數聲明的類型定義較簡單:
function sum(x: number,y: number): number { return x+y; }
注意,輸入多余的(或者少於要求的)參數,是不被允許的。
函數表達式
如果要我們現在寫一個對函數表達式(Function Expression)的定義,可能會寫成這樣:
let mySum = function (x: number, y: number): number { return x + y; };
這是可以通過編譯的,不過事實上,上面的代碼只對等號右側的匿名函數進行了類型定義,而等號左邊的 mySum
,是通過賦值操作進行類型推論而推斷出來的。如果需要我們手動給 mySum
添加類型,則應該是這樣:
let mySum: (x: number,y: number) => number=function (x: number, y:number): number{ return x+y; };
注意不要混淆了 TypeScript 中的 =>
和 ES6 中的 =>
。
在 TypeScript 的類型定義中,=>
用來表示函數的定義,左邊是輸入類型,需要用括號括起來,右邊是輸出類型。
用接口定義函數的形狀
我們也可以使用接口的方式來定義一個函數需要符合的形狀:
interface SearchFunc { (source:string, subString: string): boolean; } let mySearch:SearchFunc; mySearch = function (source: string,subString: string) { return source.search(subString) !==-1; }
剩余參數
ES6 中,可以使用 ...rest
的方式獲取函數中的剩余參數(rest 參數):
function push(array,...items) { items.forEach(function(item) { array.push(item); }); } let a=[]; push(a,1,2,3);
事實上,items
是一個數組。所以我們可以用數組的類型來定義它。
注意,rest 參數只能是最后一個參數。
重載
重載允許一個函數接受不同數量或類型的參數時,作出不同的處理。
比如,我們需要實現一個函數 reverse
,輸入數字 123
的時候,輸出反轉的數字 321
,輸入字符串 'hello'
的時候,輸出反轉的字符串 'olleh'
。
利用聯合類型,我們可以這么實現:
function reverse(x: number | string): number | string { if (typeof x === 'number') { return Number(x.toString().split('').reverse().join('')); } else if (typeof x === 'string') { return x.split('').reverse().join(''); } }
然而這樣有一個缺點,就是不能夠精確的表達,輸入為數字的時候,輸出也應該為數字,輸入為字符串的時候,輸出也應該為字符串。
這時,我們可以使用重載定義多個 reverse
的函數類型:
function reverse(x: number): number; function reverse(x: string): string; function reverse(x: number | string): number | string { if(typeof x === 'number') { return Number(x.toString().split('').reverse().join('')); } else if (typeof x === 'string') { return x.split('').reverse.join(''); } }