iT邦幫忙

第 11 屆 iT 邦幫忙鐵人賽

DAY 8
1
自我挑戰組

Typescript 初心者手札系列 第 8

【Day 08】TypeScript 資料型別 - 函式型別(Function Types)-(上)

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

  • 如何解釋基礎物件在 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)等就留待明天繼續探討囉。

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


上一篇
【Day 07】TypeScript 資料型別 - 基礎物件型別(Basic Object)
下一篇
【Day 09】TypeScript 資料型別 - 函式型別(Function Types)-(下)
系列文
Typescript 初心者手札30

1 則留言

0
c3jack
iT邦新手 5 級 ‧ 2020-01-07 09:12:59

let add: (x: number, y: number) => number = function (x: > number, y: number): number {
return x + y;
}

x: > number中的'>'是不是多的?

我要留言

立即登入留言