函數類型
為函數定義類型
給函數定義類型,包括對參數和返回值的類型定義:
function add(arg1: number, arg2: number): number { return arg1 + arg2 } // 箭頭函數 const add = (arg1: number, arg2:number):number => { return arg1 + arg2 }
如果這里省略參數的類型,typescript 會默認這個參數是 any 類型;如果省略返回值的類型,那么當函數無返回值時,typescript 默認函數返回值是 void 類型,當函數有返回值時,typescript 會根據我們定義的邏輯推斷出返回值的類型。
完整的函數類型
可以定義一個完整的函數類型,它包括參數類型和返回值類型,如下:
// 定義變量 add,指定類型為 (x: number, y: number)=> number let add:(x: number, y: number)=> number // 給變量賦值函數,其符合上面定義的函數類型 add = (arg1: number, arg2: number) => arg1 + arg2
可以看到函數類型中的參數名和實際函數的參數名不一致,這里需要注意,只要參數類型是匹配的,那么就認為它是有效的函數類型,而不在乎參數名是否正確。
使用接口定義函數類型
使用接口可以清晰地定義函數類型:
interface Add{
(x: number, y: number): number
}
let add:Add = (arg1: number, arg2: number): number => arg1 + arg2
使用類型別名定義函數
類型別名是使用 type 關鍵字定義一個類型,可以用來定義函數類型:
type Add = (x: number, y: number) => number
let add:Add = (arg1: number, arg2: number): number => arg1 + arg2
函數參數
可選參數
定義函數類型時,使用 ? 來指定可選參數,但需要注意的是,可選參數必須放在必須參數后面,這跟在接口中定義可選參數不一樣,在定義接口時,可選參數的位置在前在后都無所謂。
// error,x 是可選參數,放在必選參數 y 之前是錯誤的 type Add = (x?: number, y: number) => number
默認參數
默認參數與在 es6 中的實現一樣,直接用 = 給出默認值。需要注意兩個地方:一是默認參數的位置不講究,它放在必選參數前后都行;二是當給默認參數指定默認值時,typescript 會識別默認參數的類型,當我們在調用函數時,如果給這個帶默認值的參數傳來別的類型的參數時則會報錯:
let add = (x: number, y = 2) => { return x + y } add(1, '2') // error,類型“"2"”的參數不能賦給類型“number”的參數
可以顯示地給默認參數指定類型:
let add = (x: number, y: number = 2) => { return x + y }
剩余參數
對於不知道會傳入多少參數的函數來說,在 javascript 中會使用 arguments 來獲取參數列表。在 typescript 中,使用跟 es6 中一樣的 ... 來將剩余參數收集到一個變量中。
const handleData = (arg1, ...arg2) => { console.log(arg2) } handleData(1,2,3,4,5,6) // [2,3,4,5,6]
給參數指定類型:
const handleData = (arg1: number, ...arg2: number[]) => {
console.log(arg2)
}
函數重載
在一些強類型語言中,函數重載是指定義幾個函數名相同,但參數個數或類型不同的函數,在調用時傳入不同的參數,編譯器會自動調用適合的函數。而在 javascript 中,是沒有函數重載的,我們可以在函數內部判斷參數的個數和類型來指定不同的處理邏輯。
const handleData = (value: any)=>{ if(typeof value === 'string'){ return value.split('') }else{ return value.toString().split('').join('_') } } console.log(handleData('hello')) // ["h", "e", "l", "l", "o"] console.log(handleData(123)) // 1_2_3
我們需要將上面這種情況在類型系統中表示出來。在 typescript 中有函數重載的概念,但不是定義幾個同名實體函數,而是通過為一個函數指定多個函數類型定義,從而對函數調用的返回值進行檢查。代碼如下:
function handleData(value: string): string[] function handleData(value: number): string function handleData(value: any):any { if(typeof value === 'string'){ return value.split('') }else{ return value.toString().split('').join('_') } } console.log(handleData('hello')) // ["h", "e", "l", "l", "o"] console.log(handleData(123)) // 1_2_3 console.log(handleData(false)) // error,類型“false”的參數不能賦給類型“string”的參數,類型“false”的參數不能賦給類型“number”的參數
首先使用 function 關鍵字定義了兩個同名函數,這兩個函數沒有實際的函數體邏輯,只定義了函數名,參數及參數類型以及函數的返回值類型,這兩個定義稱為 “函數重載”。第三個使用 function 定義的同名函數,是一個完整的實體函數,它不算重載。這三個定義組成一個函數。當函數調用時,會從上到下匹配重載,當匹配不到時會報錯。