一、TypeScript函数类型的基本使用
在使用函数的过程中,函数是否也可以有自己的类型。
只需要编写函数类型的表达式(Function Type Expressions
),来表示函数类型。
1.1 函数类型的定义
type calcFunType = (num1: number, num2: number) => void
代表定义了一个函数类型,函数要求有两个number类型的参数,并且函数没有返回值
注意点:
官方文档明确强调,函数参数的参数名称不可以省略
1.2 函数作为参数时, 在参数中如何编写类型
type FooFnType = () => void
function bar(fn: FooFnType) {
fn()
}
代表bar函数需要接收一个无参五返回值的函数
1.3 定义常量时, 编写函数的类型
type AddFnType = (num1: number, num2: number) => number
const add: AddFnType = (a1: number, a2: number) => {
return a1 + a2
}
明确add变量的类型是一个函数类型
并且此函数类型求有两个number类型的参数,并且函数需要有一个number类型的返回值
二、函数的返回值
2.1 函数有返回值
function sum(num1: number, num2: number):number {
return num1 + num2
}
这个类型注解出现在函数列表的后面
通常情况下不需要返回类型注解,因为TypeScript会根据 return 返回值推断函数的 返回类型
而某些第三方库处于方便理解,会明确指定返回类型,具体写不写看公司规范
2.2 函数无返回值
void
通常用来指定一个函数是没有返回值的,即如果函数没有返回值,那么它的返回值就是void
类型。
function sum(num1: number, num2: number): void {
console.log(num1 + num2)
}
上面声明了一个函数,需要接收两个数字类型参数num1和num2,并且没有返回值。
但是即使不写void,TypeScript也会推断出来这个函数是没有返回值的,开发中习惯上是不写
三、函数参数的可选类型
有时候,函数并不要求每个参数都要去传递,而是可以选择只传一部分参数。
function foo(x: number, y?: number) {
}
y? 就代表y参数是一个可选参数,可以选择不传递
y?: number 等同于组合类型 undefined | number
可选类型是必须写在必选类型的后面的
四、函数参数的默认值
从ES6
开始,JavaScript
是支持默认参数的,TypeScript
也是支持默认参数的。
function foo(y: number, x: number = 20) {
console.log(x, y)
}
foo(30)
当参数x不传时,x的默认值就是20
这个时候x的类型其实是 undefined 和 number 类型的联合类型
注意点:
函数各类型参数的编写位置
先写必传参数 - 然后写有默认值的参数 - 最后写可选参数
五、函数的剩余参数
从ES6
开始,JavaScript
也支持剩余参数,剩余参数语法允许我们将一个不定数量的参数放到一个数组中。
function sum(initalNum: number, ...nums: number[]) {
let total = initalNum
for (const num of nums) {
total += num
}
return total
}
console.log(sum(20, 30))
console.log(sum(20, 30, 40))
...nums: number[]
相当于可以传入任意类型的参数它们会被封装到
nums
这个数组当中
六、this的默认推导类型
因为this在不同的情况下会绑定不同的值,TypeScript是如何处理this呢?
6.1 this可以被推导出来的情况
const info = {
eating() {
console.log("eating...")
}
}
info.eating()
这种情况下,this是可以被推导出来,eating()函数的调用者info对象就是TypeScript推导出来的this
6.2 this不能被推导出来的情况
function eating() {
console.log("eating...")
}
const info = {
eating
}
info.eating()
这段代码运行将会报错。
TypeScript
进行类型检测的目的是让我们的代码更加的安全;
所以这里对于eating
的调用来说,虽然将其放到了info
中,通过info
去调用,this依然是指向info
对象。
对于TypeScript
编译器来说,这样是非常不安全的。因为我们可能直接调用函数,或者通过对象来 调用函数。
6.3 手动指定this的类型
当遇到this
不能被推导出来的时候,通常TypeScript
会要求我们明确的指定函数中this
的类型。
1)指定一个没有属性的this类型
type thisType = {} // 定义this类型为一个没有属性的对象
function eating(this: thisType, message: string) { // 指定该函数的this类型
console.log("eating", message)
}
const info = {
eating: eating
};
// 隐式绑定
info.eating("food") //info对象要满足thisType约定的对象类型,才可以去调用eating方法
2)指定一个有属性的this类型
type ThisType = { name: string }; // 定义this类型为一个只有name属性的对象
function eating(this: ThisType, message: string) { // 指定该函数的this类型
console.log(this.name + " eating", message);
}
const info = {
name: 'zs'
eating: eating,
};
// 隐式绑定
info.eating("food"); // info对象要满足thisType约定的对象类型,即拥有一个字符串类型的name属性
// 才可以去调用eating方法
3)显示绑定
type ThisType = { name: string }; // 定义this类型为一个只有name属性的对象
function eating(this: ThisType, message: string) { // 指定该函数的this类型
console.log(this.name + " eating", message);
}
const info = {
name: 'zs'
eating: eating,
};
// 显示绑定
eating.call({name: "ls"}, "food") // 手动指定this指定的对象是谁
eating.apply({name: "zl"}, "food")
七、函数的重载
在ts
中,可以去编写不同的重载签名(overload signatures
)表示函数可以以不同的方式进行调用。
一般是编写两个或者以上的重载签名,再去编写一个通用的函数以及实现。
// 定义函数重载签名
function add(num1: number, num2: number): number; // 没函数体,没有具体实现
function add(num1: string, num2: string): string;
// 具体的重载函数实现
function add(num1: any, num2: any): any {
if (typeof num1 === 'string' && typeof num2 === 'string') {
return num1.length + num2.length
}
return num1 + num2
}
console.log(add(30, 30)) // 两个数值类型,会调用参数和返回值都是number的重载
console.log(add("abc", "def")) // 两个字符串类型,会调用参数和返回值都是string的重载
函数重载的特点:
-
函数名称相同,但是参数不同的几个函数,就是函数重载
-
参数不同:参数的个数不同,或者参数的类型不同,都称为参数不同
有实现体的函数,是不能直接被调用的:
比如对于上面的add
函数,直接像下面这样子去调用时不行的。
add(20, "30")
因为调用sum
函数会在重载签名中从上到下依次匹配,都没有匹配到,就会报错,并不会执行重载函数的实现函数。