一.类型
函数的类型分为两部分:
参数:各个参数的类型
返回值:返回值的类型
例如:
带类型的函数声明足够表达一个函数的类型信息,但无法复用。那么有办法复用一个函数的类型吗?
有。把类型抽离出来就可以复用了,姑且称之为类型描述
类型描述
可以通过箭头函数语法描述函数的类型:
箭头(=>)左侧是参数及其类型,右侧是返回值类型,都是语法结构的一部分,不可缺省:
P.S.注意到上面示例只声明了一份类型,是因为右边匿名函数的类型能够根据左侧类型声明自动推断出来,称之为语境类型推断(contextual typing)
另外,类型描述里的参数名只是可读性需要,不要求类型描述中的参数名与真实参数名一致,例如:
P.S.实际上,还有另一种描述函数类型的方式:接口,具体见接口_TypeScript笔记3
二.参数
可选参数
JavaScript里参数默认都是可选的(不传的默认undefined),而TypeScript认为每个参数都是必填的,除非显式声明可选参数:
与可选属性的语法类似,紧跟在参数名后面的?表示该参数可选,并且要求可选参数必须出现在必填参数之后(所以想要firstName可选,lastName必填的话,只能改变参数顺序)
默认参数
默认参数语法与ES规范一致,例如:
从含义上看,默认参数当然是可选的(不填就走默认值),因此,可以认为默认参数是特殊的可选参数,甚至连类型描述也是兼容的:
二者类型完全一致,所以,类型描述并不能完整表达默认参数(仅能表达出可选的含义,默认值丢失了)
另一个区别是,默认参数不必出现在必填参数之后,例如:
显式传入undefined占位,具体见三.默认参数
剩余参数
与ES6不定参数语法一致:
剩余参数也是可选的,相当于不限数量的可选参数:
另外,类型描述中也采用了相同的语法:
三.this
this在JavaScript不那么容易驾驭,例如:
this的类型
特殊的,TypeScript能够描述this的类型,例如:
其中this是个假参数,并且要求必须作为第一个参数:
this也像普通参数一样进行类型检查,能够提前暴露出类似的错误:
P.S.另外,可以开启--noImplicitThis编译选项,强制要求所有this必须有显式的类型声明
四.重载
类似于Java里的重载:
(摘自Types of polymorphism in java- Runtime and Compile time polymorphism)
简言之,能让同名函数的不同版本共存。不同版本体现在参数差异上:
参数数量
参数顺序
参数类型
这3个特征中只要有一个不同就算重载。如果都相同,就认为是重复声明的方法(Duplicate Method),并抛出编译错误:
TypeScript里也有重载的概念,但与Java重载有一些差异,例如:
看起来非常合理,但在TypeScript里会报错:
编译结果是这样(TypeScript编译报错并不影响代码生成,具体见类型系统):
因为JavaScript不支持重载,(同一作用域下的)方法会覆盖掉先声明的同名方法,无论函数签名是否相同。因此,TypeScript里的重载能力受限,仅体现在类型上:
同样,这些重载类型声明仅作用于编译时,因此也有类似于模式匹配的特性:
上例中先声明的更宽泛的any版本成功匹配,因此并没有如预期地匹配到更准确的number版本,
所以,应该把最宽泛的版本放到最后声明: