函数是重要的组成部分,并且函数可以作为一等公⺠(可以作为参数,也可以作为返回值进行传递),所以函数也有自己的数据类型
函数类型表达式
我们可以编写函数类型的表达式(Function Type Expressions),来表示函数类型
# (参数列表) => 返回值
// 在参数列表中,函数的形参名是不能省略的
// (number) => number 会被解析为 (number: any) => number
type Sum = (num1: number, num2: number) => number
const sum: Sum = (num1, num2) => num1 + num2
调用签名
在 JavaScript 中,函数除了可以被调用,自己也是可以有属性值,然而函数类型表达式并不能支持声明属性
如果我们想描述一个带有属性的函数,我们可以在一个对象类型中写一个调用签名(call signature)
调用签名的语法跟函数类型表达式稍有不同,在参数列表和返回的类型之间用的是 : 而不是 =>
interface ISum {
name?: string
age?: number
(num1: number, num2: number): number
}
const sum: ISum = (num1, num2) => num1 + num2
sum.name = 'Klaus'
sum.age = 23
当我们仅仅只是需要描述函数本身的时候,直接使用函数调用表达式即可
但是如果在描述函数的时候,需要将其作为对象来进行使用,也就是除了函数调用功能外,还需要使用函数上的某些属性的时候,就可以使用函数的调用签名
构造签名
JavaScript 函数也可以使用 new 操作符调用,当被调用的时候,TypeScript 会认为这是一个构造函数(constructors),因为他们会产生一个新对象
function foo() {}
// 在TS中,默认情况下,任何一个函数都是可以使用new关键字来进行调用的
// 只不过返回的实例类型都是any
const baz = new foo()
如果想要获取对应的更为具体的类型,你可以写一个构造签名( Construct Signatures ),方法是在调用签名前面加一个 new 关键词
class Person {
name: string
constructor(name) {
this.name = name
}
}
interface IPerson {
// 表示该类型 可以被new调用 并返回Person类的实例
new (name: string) : Person
}
function createPerson(fn: IPerson) {
return new fn('Klaus')
}
// 构造函数本质上也是一个函数
createPerson(Person)
参数
参数个数
// 对于函数类型,在赋值的时候,参数个数只要类型匹配,且对应位置类型格式匹配即可
// 对于参数个数,个数小于等于可以预先设定的个数都是可以的
type Fun = (num1: number, num2: number) => number
function foo1(num: number) {
return num
}
function foo2(num1: number, num2: number) {
return num1 + num2
}
function foo3(num1: number, num2: number, num3: number) {
return num1 + num2 + num3
}
let baz: Fun
// foo1 和 foo2 都是可以赋值给Fun的
// foo1 和 foo2 都是 Fun类型的子类型
baz = foo1
baz = foo2
// baz = foo3 // error
type Fun = (num1: number, num2: number) => number
function foo1(num: number) {
return num
}
let baz: Fun
baz = foo1
// 函数赋值的时候,参数个数可以省略
// 但是在调用的时候,参数个数不能省略
// 因为虽然子类型可以赋值给父类型,但是最终变量的类型是父类型
// 也就是说此时baz的类型是(num1: number, num2: number) => number
// 而不是(num1: number) => number
baz(10, 20)
可选参数
// 函数参数后加上 问号 表示这个参数是一个可选参数
// num2 的类型 会被识别为 设定的类型 | undefined
// 在这里就是 number | undefined
// 可选参数是那些可能不传的参数,所以可选参数必须放到必传参数的后边
function foo(num1: number, num2?: number) {}
默认参数
// num2 是默认参数
// 1. 对于默认参数 类型是可以省略的,因此此时就可以自动被推导出来
// 2. 对于默认参数 在实际调用的时候,可以接收值为undefined的实参
// 因为只有当传入的值是undefined的时候,函数才会去使用对应的默认参数
function foo(num1: number, num2 = 300) {}
剩余参数
// 可以使用一个数组类型 来定义 剩余参数
function foo(...args: (string | number)[]) {}
重载
在TypeScript中,我们可以去编写不同的重载签名(overload signatures)来表示函数可以以不同的方式进行调用
一般是编写两个或者以上的重载签名,再去编写一个通用的函数以及实现
TS会根据我们传入的参数类型来决定执行函数体时,到底执行哪一个函数的重载签名
所以有实现体的那个函数的类型在实际匹配中是不会被使用的
// 函数重载签名 --- 只能通过function来定义函数重载签名
function sum(num1: number, num2: number): number
function sum(str1: string, str2: string): string
// 函数实现
function sum(arg1, arg2) {
return arg1 + arg2
}
sum(1, 2)
sum('Hello', 'Workd')
// 没有对应的重载签名可以被匹配上
// sum(1, 'Hello') // error