功能
与 JavaScript 一样typescript函数对象,TypeScript 函数可以创建命名函数和匿名函数。
// 具名函数
function add (x, y) {
return x + y;
}
// 匿名函数
let myAdd = function (x, y) { return x + y; }
// 表达式中的 具名函数 在javascript中存在这样一个限制,表达式中的 具名函数只识别为匿名函数 ,而忽略它的函数名
let fn = function add (x, y) { return x + y; }
function add (x: number, y: number): number {
return x + y;
}
let myAdd = function(x: number, y: number): number { return x + y; };
注意:为每个参数添加类型后,不需要为函数本身添加返回值类型,因为 TypeScript 可以根据返回语句手动推断返回值类型
函数重载
由于JavaScript是动态语言,我们一般会使用不同类型的参数来调用同一个函数,函数会根据不同的参数返回不同类型的调用结果:
function add (x, y) {
return x + y;
}
add(1, 2); // 3
add("1", "2"); // "12"
上述代码在 JS 环境中运行没有问题,而如果在 TypeScript 环境中且 TypeScript 编译器启用了 noImplicitAny(将 TypeScript 从可选类型语言转换为强制类型验证语言)配置项,则上述代码会提示出现以下错误消息:
Parameter 'x' implicitly has an 'any' type.
Parameter 'y' implicitly has an 'any' type.
此信息告诉我们参数 x 和参数 y 隐式具有 any 类型。 为了解决这个问题,我们可以为参数设置一个类型。由于我们希望add函数同时支持字符串和数字类型,所以我们可以定义一个字符串|数字联合类型
function add (x: number | string, y: number | string) {
if (typeof x === 'string' || typeof y === 'string') {
return x.toString() + y.toString();
}
return x + y;
}
设置关节类型后,之前的错误信息消失,然后下一步:
let result = add('hearts', 'spades');
result.split(' ');
我们贸然以为结果类型是string,然后就可以正常对string对象使用split方法了。 结果又出现了新问题typescript函数对象,提示number类型对象上不存在split属性。
Property 'split' does not exist on type 'string | number'.
Property 'split' does not exist on type 'number'.
怎么处理呢?
在这种情况下,可以使用函数重载。 可以为同一个函数提供多个函数类型定义以进行函数重载(相同的函数名称、不同数量或类型的参数、或相同数量但参数顺序不同的参数)。
如何定义呢?
重载签名定义了函数的实际参数和返回类型,并且没有函数体。
一个函数可以有多个重载签名:主要是为了准确显示函数的输入和输出,对应调用函数的不同形式。
据悉,实现签名还有参数类型和返回类型,还有实现函数体,并且只能有一个实现签名。
签名的实现主要是全量定义所有的输入输出类型,避免TS编译错误。 签名的实现就是整个函数实现的整个逻辑。
喜欢:
type Types = number | string;
// 重载签名
function add(x: number, y: number): number;
function add(x: string, y: string): string;
function add(x: string, y: number): string;
function add(x: number, y: string): string;
function add(x: Types, y: Types) {
if (typeof x === 'string' || typeof y === 'string') {
return x.toString() + y.toString();
}
return x + y;
}
const result = add('hearts', ' spades');
result.split(' ');
编译成功,编译结果如下:
上面定义了 4 个重载签名和 1 个实现签名。
注意:当 TypeScript 编译器处理函数重载时,它会查找重载列表并尝试使用第一个重载定义。 如果匹配就使用它。 因此,在定义重载时,请务必将最精确的定义放在顶部。
其他:
从编译结果可以看出,JavaScript作为动态语言,不存在函数重载这个词。 原因如下:
由于在语言层面很难手动重载,利用其动态特性,我们可以在代码中自动检测输入参数的类型,或者通过arguments获取参数的个数,从而可以根据不同的输入执行不同的操作参数。
参考