函数类型
为函数定义类型
给函数定义类型,包括对参数和返回值的类型定义:
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 定义的同名函数,是一个完整的实体函数,它不算重载。这三个定义组成一个函数。当函数调用时,会从上到下匹配重载,当匹配不到时会报错。