该系列文章是本人阅读阮一峰老师的《TypeScript教程》学习笔记,欢迎各位大佬指出不正确的地方,感谢!
简介
函数的类型声明,需要在声明函数的时候,给出参数的类型和返回值的类型。
如果不指定参数的类型,TS会推断参数类型;如果缺乏足够信息,就会推断该参数的类型为any。
返回值的类型通常可以不写,因为TS自己会推断出来。有时候出于文档目的,或者是为了防止不小心改掉返回值,还是会写返回值的类型。
变量被赋值函数
通过函数类型推断变量类型
使用箭头函数的形式为变量指定类型
指定类型需注意:
- 函数的参数要放在圆括号里面,不放会报错;
- 类型里面的参数名是必须的。
函数类型里面的参数名与实际参数名可以不一致。
可以用type命令为函数类型定义一个别名,便于指定给其他变量。
函数的实际参数个数,可以少于类型指定的参数个数,但不能多于,即TS允许省略参数,这一点与JS保持一致。
如果一个变量要套用另一个函数类型,可以使用typeof运算符。任何需要类型的地方,都可以使用typeof运算符从值中获取类型。
函数类型可以采用对象的写法(基本遵守对象规则):
这种写法的函数参数与返回值之间,间隔符号是英文冒号(:),而不是正常写法的箭头=>。
这种写法适用于函数本身存在属性的情况下:
函数类型也可以用Interface来声明,这算是对象写法的翻版。
Function类型(不建议使用)
TS提供Function类型表示函数,任何函数都属于这个类型。
Function类型的值可以直接执行。
Function类型的函数可以接受任意数量的参数,每个参数的类型都是any,返回值的类型也是any,代表没有任何越约束,所以不建议使用这个类型。
箭头函数
箭头函数的类型写法与普通函数类似。
类型写在箭头函数的定义里面,与使用箭头函数表示函数类型,写法有所不同。
上面所描述的是箭头函数在定义的时候与作为参数定义类型的时候的不同之处。定义箭头函数的时候返回类型是写在参数右括号后面,定义箭头函数参数的时候返回类型是写在=>后面。
另外一个典型的例子:
可选参数
如果函数的某个参数可以省略,则在参数名后面加问号表示。参数名带问号,则表示该参数的类型实际上是“原始类型|undefined”,它可能是undefined。
但反过来不成立,类型显示设为undefined的参数,则不能省略。
函数的可选参数只能在参数列表的尾部,跟在必选参数的后面。如果前部参数有可能为空,这时只能显示注明该参数类型可能为undefined。
函数内部用到可选参数时,要先判断是否存在。
参数默认值
TS函数的参数默认值写法与JS一致,存在默认值的参数的类型可以省略。
可选参数和默认值不能同时使用。
设有默认值的参数,如果传入undefined,也会触发默认值。
具有默认值的参数如果不位于参数列表的末尾,调用时也不能省略,如果要触发默认值,必须显式传入undefined。
参数解构
函数参数如果存在变量结构,类型写法如下:
参数结构可以结合类型别名(type命令)一起使用,代码看起来更简洁:
rest参数
rest参数表示函数剩余的所有参数,它可以是数组(剩余函数类型相同),也可以是元组(剩余参数类型不同);
注意,元祖需要声明每个剩余参数的类型。如果元组里面的参数是可选的,则要使用可选参数。
rest参数甚至可以嵌套。
rest参数可以与变量结构结合使用。
readonly只读参数
如果函数内部不能修改某个参数,可以在函数定义时,在参数类型前面加上readonly关键字,表示这个是只读参数。
void类型
void类型表示函数没有返回值,如果返回其它值编译就会报错。
void类型允许返回undefined或null。
如果开启了strictNullChecks编译选项,那么void类型只允许返回undefined。如果返回null,就会报错。这是因为JS规定,如果函数没有返回值,就等同于返回undefined。
需要特别注意,如果变量、对象方法、函数参数的类型是void类型的函数,那么并不代表不能赋值为有返回值的函数。恰恰相反,该变量、对象方法和函数参数可以接受返回任意值的函数,这时并不会报错。
举个例子来体现这样设计的现实意义:
数组方法Array.prototype.forEach(fn)的参数fn是一个函数,而且这个函数应该没有返回值,即返回值类型为void。
但实际应用中,很多时候传入的函数都是有返回值,但是它的返回值不重要或者不产生作用。
如果后面使用了这个函数的返回值,就违反了约定,则会报错。
注意,这种情况仅限于变量、对象方法和函数参数,函数字面量如果声明了返回值是void类型,还是不能有返回值。
除了函数,其它变量声明为void类型没有多大意义,因为这时只能赋值为undefined或null(如果没有开启strictNullChecks)。
never类型
never类型表示肯定不会出现的值。它用在函数的返回值,就表示某个函数肯定不会返回值,即函数不会正常执行结束。
主要有以下两种情况:
- 抛出错误的函数:只有抛出错误才是never类型,显示用return返回一个Error对象,返回值就不是never类型;
2. 无限执行的函数
never类型不同于void类型。前者表示函数没有执行结束,不可能有返回值;后者表示函数正常执行结束,但不返回值或者返回undefined。
如果程序中调用了一个返回值类型为never的函数,那么就意味着程序会在该函数的调用位置终止,永远不会继续执行后续的代码。
局部类型
函数内部允许声明其它类型,该类型只在函数内部有效,称为局部类型。
高阶函数
一个函数的返回值还是一个函数,那么前一个函数就称为高阶函数。
函数重载
有些函数可以接受不同类型或个数的参数,并且根据参数的不同,会有不同的函数的行为。这种根据参数类型不同,执行不同逻辑的行为,称为函数重载。
该函数内部有处理字符串和数组的两套逻辑,根据参数类型的不同,分别执行对应的逻辑,这就叫“函数重载”。
TS对于“重载函数”的类型声明方法是,逐一定义每一种情况的类型。
有一些编程语言允许不同的函数参数对应不同的函数实现。但JS函数只能有一个实现,必须在这个实现当中,处理不同的参数。因此,函数体内部就需要判断参数的类型及个数,并根据判断结果执行不同的操作。
注意,重载的个人类型描述于函数的具体实现之间,不能有其他代码,否则报错。
虽然函数的具体实现里面,有完整的类型声明。但是,函数实际调用的类型,以前面的类型声明为准。
函数重载的每个类型声明之间,以及类型声明与函数实现的类型之间,不能有冲突。
重载声明的排序很重要,因为TS是按照顺序进行检查的,一旦发现符合某个类型声明,就不再往下检查了,所以类型最宽的声明应该放在最后面,防止覆盖其他类型声明。
对象的方法也可以使用重载。
函数重载也可以用来精确描述参数与返回值之间的关系。
由于函数重载是一种比较复杂的看类型声明方法,为了降低复杂性,应该有限使用联合类型替代函数重载。
构造函数
JS语言使用构造函数,生成对象的实例。构造函数最大的特点就是必须使用new命令调用。
构造函数的类型写法,就是在参数列表前面加上new命令。
构造函数的另外一种类型写法,就是采用对象形式。
某些函数既是构造函数,又可以当作普通函数使用,比如Date()。这时,类型声明可以写成下面这样。