閱讀今天的文章前,先回顧一下昨天的學習,回答看看:
- 如何解釋基礎物件在 TypeScript 的型別推論和型別註記機制?
- null 和 undefined 值在strictNullCheck 不同設定下,型別推斷會有什麼影響?
如果有點不清楚答案的話,可以看看 Day07 的文章喔!
和 JS 一樣,在 TS 中一樣可以創建有名字的函式和匿名函式,分別稱為函式宣告(Function Declaration)和函式表達式(Function Expression)。一個函式會有輸入和輸出,在 TS 中 輸入的參數以及回傳值的型別都會被檢視。
// 函式宣告(有名字的函式)
function add(x, y) {
return x + y;
}
// 函式表達式(匿名函式)
let myAdd = function(x, y) { return x + y; };
但這時候 TS 出現了提醒,參數 x 和 y 下方出現了底線
進一步查看提醒的訊息,發現 TS 明顯對於我們的函數參數型別很有意見
TS 對於函式參數的型別隱性推論結果是 any ,但卻建議更好的型別,為什麼呢?
首先,可以想想看:
如果參數推論是 any,那麼函式輸出的型別推論又會是什麼呢?提示:通常函式輸出(output)都會跟輸入(input)有關。
似乎應該也是 any ? 但 any 不就代表任何型別都可以了嗎? 這樣 TS 也不用檢測啦!是的,TS 官網中有提及 any 在 TS 裡會跳過型別檢測,容易引發非預期行為的機率會上升。因此,我們應該要儘量避免 any 的出現(僅少部分狀況會使用 any)。
再回來看看上面的程式碼,函數的作用似乎可以用作數字的相加,咦,但是字串的連接似乎也可以說得通,這樣有點沒節操,嗯湯。
function add(x, y) {
return x + y;
}
// 數字相加
add(1,2) //3
//字串相加
add('1','2') //12
事實上,從程式碼 TS 根本無從推論函式輸入的參數是什麼型別,因此,TS 最後的方式就是把參數一率推論為 any,但是 TS 會提醒開發者「是不是忘記註記參數的型別呢?如果沒有註記,我只能把這個函式的參數當做 any 囉!」
註:大部分的情況下,只要定義任何函式,TS 通常會無條件推論函式內的參數為 any 型別。
雖然 TS 有貼心的提醒,但如果不理會直接編譯,其實並不會報錯喔!除非開啟了 tsconfig.json 檔中的 noImplicitAny 設定,表示 TS 會嚴格檢視不允許Implicit Any 出現,如此,只要參數沒有明確註記型別就會報錯。
那現在就來試試看在函式上加上型別註記吧!把函式的兩個參數 x 和 y 分別註記為數字型別如下:
function add(x: number, y: number) {
return x + y;
}
這個時候把鼠標滑到 add 上看一下,神奇的事情發生了
咦,原本不是只有標註兩個參數的型別而已,怎麼 TS 已經推論出回傳的資料型別了呢? 是的,TS 就是如此聰明!大部分情況下,只要提供函式參數的註記,輸出就可以間接被 TypeScript 推論出來。
當然,回傳值也可以使用型別註記,直接在放置參數的()後方註記回傳值型別
//函式宣告式
function add(x: number, y: number):number {
return x + y;
}
// 函式表達式(匿名函式)
let add = function(x: number, y: number) {
return x + y;
};
實際上,上面的程式碼只對等號右邊的匿名函式進行型別註記,而等號左邊的add是透過等號賦值進行型別推論而來的。完整的寫法應該是:
let add: (x: number, y: number) => number = function (x: > number, y: number): number { return x + y; }
注意不要混淆了 TypeScript 中的 => 和 ES6 中的 =>唷!
這裡的=>用來表示函式的型別定義,左邊是輸入型別,需要用括號刮起來,右邊則是輸出型別。但其實只在等式一邊有型別,TS 編譯器就可以正確辨識型別了,因此不太會使用裹腳布長的完整寫法。
當傳入多餘(或者少於)的參數都會報錯
function add(x: number, y: number):number {
return x + y;
}
add(1) //Error: Expected 2 arguments, but got 1.
add(1,2)
add(1,2,3) //Error: Expected 2 arguments, but got 3.
那如果把參數註記成 any 呢?
function add(x: any, y: any):number {
return x + y;
}
答案是可以的,TS 並不會報錯,但是這是非常不推薦的寫法,因為只要是 any TS 就不會做任何型別檢查,這樣也喪失使用 TS 型別系統的意義了。
今天先簡單介紹函式的型別推論和註記機制,然而,在 TS 中函式有一些特殊的機制,像是:函式沒有回傳值狀況、可選參數、預設參數、剩餘參數(rest parameter)及函式重載(overloads)等就留待明天繼續探討囉。
如有錯誤的地方,還請留言告知,我會盡快修改調整,感謝:)
let add: (x: number, y: number) => number = function (x: > number, y: number): number {
return x + y;
}
x: > number中的'>'是不是多的?