一、函数类型
在JavaScript开发中,函数是重要的组成部分,并且函数可以作为一等公民(可以作为参数,也可以作为返回值进 行传递)
那么在使用函数的过程中,函数是否也可以有自己的类型呢?
我们可以编写函数类型的表达式(Function Type Expressions),来表示函数类型;
function foo() {}function foo2(fn: () => void) {fn();}foo2(foo);
() => void表示函数类型
举例:
type Func = (n1: number, n2: number) => void;function calc(num1: number, num2: number, fn: Func) {console.log(fn(num1, num2));}//这么写num1 num2是默认的any类型function add(num1, num2) {return num1 + num2;}calc(20, 30, add);//这样写的话num1 num2就是number类型 因为fn是Func类型 Func中定义了参数类型calc(20, 30, function (n1, n2) {return n1 * n2;});
应该能绕明白吧
函数类型解析
在上面的语法中 (num1: number, num2: number) => void,代表的就是一个函数类型:
接收两个参数的函数:num1和num2,并且都是number类型
并且这个函数是没有返回值的,所以是void
在某些语言中,可能参数名称num1和num2是可以省略,但是TypeScript是不可以的:

参数的可选类型
我们可以指定某个参数是可选的
这个时候这个参数y依然是有类型的,它是什么类型呢? number | undefined
另外可选类型需要在必传参数的后面:
//不报错function print(x: number, y?: number) {return x + y;}//报错// function print1(x?: number, y: number) {// return x + y;// }
默认参数
function print(x: number, y: number = 100) {return x + y;}print(10, 20); //30print(10, undefined); //110
从ES6开始,JavaScript是支持默认参数的,TypeScript也是支持默认参数的
这个时候y的类型其实是 undefined 和 number 类型的联合。
剩余参数
从ES6开始,JavaScript也支持剩余参数,剩余参数语法允许我们将一个不定数量的参数放到一个数组中。
function sum(...nums: number[]) {let total = 0;for (const i of nums) {total += i;}return total;}sum(10, 20, 30); //60console.log(sum(10, 20, 30, 40, 50)); //150
this类型
const info = {name: 'xxx',say() {console.log(this.name);},};info.say(); //xxx
上面的代码是可以正常运行的,也就是TypeScript在编译时,认为我们的this是可以正确去使用的
TypeScript认为函数say有一个对应的this的外部对象 info,所以在使用时,就会把this当做该对象。
function foo() {console.log(this.name);}const info1 = {name: 'yyy',foo: foo,};info1.foo(); //报错
强调一下,TypeScript进行类型检测的目的是让我们的代码更加的安全
- 所以这里对于foo的调用来说,我们虽然将其放到了info中,通过info去调用,this依然是指向info对象的
- 但是对于TypeScript编译器来说,这个代码是非常不安全的,因为我们也有可能直接调用函数,或者通过别的对象来调用函数
- 所以这里在编译时会报错,要求我们指定this类型
指定this的类型
type NameType = {name: string;};function foo(this: NameType) {console.log(this.name);}const info1 = {name: 'yyy',foo: foo,};info1.foo(); //yyy
函数的重载
TypeScript中,如果我们编写了一个add函数,希望可以对字符串和数字类型进行相加,应该如何编写呢?
我们可能会这样来编写,但是其实是错误的:

那么这个代码应该如何去编写呢?
- 在TypeScript中,我们可以去编写不同的重载签名(overload signatures)来表示函数可以以不同的方式进行调用
- 一般是编写两个或者以上的重载签名,再去编写一个通用的函数以及实现
function sum(n1: number, n2: number): number;function sum(n1: string, n2: string): number;function sum(n1: string, n2: number): number;function sum(n1: any, n2: any) {return n1 + n2;}console.log(sum(20, 30)); //50console.log(sum('abc', 'cba')); //abccbaconsole.log(sum('abc', 123)); //abc123
在我们调用sum的时候,它会根据我们传入的参数类型来决定执行函数体时,到底执行哪一个函数的重载签名
注意,有实现体的函数,是不能直接被调用的
联合类型和重载
有一个需求:定义一个函数,可以传入字符串或者数组,获取它们的长度。
//联合类型实现function getLength(n: string | any[]) {return n.length;}//函数重载实现function getLength1(n: string): number;function getLength1(n: any[]): number;function getLength1(n: any) {return n.length;}
开发中我们选择使用哪一种呢?
- 在可能的情况下,尽量选择使用联合类型来实现
