考虑这样一个简单的函数:
export const add = (num?: number) => {
const adder = (n: number) => {
if (!n) {
return num;
}
num = (num && num + n) || n;
return adder;
};
return adder;
};
示例用法:
const result = add(1)(2)(3)() // => 6
当被调用时,add
将返回下一个使用另一个数字的函数,或者如果没有传递数字,则返回最终和。
这在普通js中可以正常工作,但对于typescript,这将导致一个错误:
此表达式不可调用。并非类型'number|((n?:number|undefined(=>的所有组成部分;(x?:数字|未定义(=>数字|…('是可调用的。类型"number"没有呼叫签名。ts(2349(
这是因为TS无法确定下一次迭代是返回函数还是返回数字。
问题:
如何正确键入此函数,使TS不会抛出错误?
当然可以描述add()
的调用签名,以便调用方看到所需的行为。不幸的是,TypeScript编译器将无法验证add()
的实现满足此调用签名;要做到这一点,我们需要对重载实现或泛型条件类型的行为更加明智。这意味着我们至少需要一种类型断言或类似的类型松动技术来抑制编译器错误。
不管怎样,假设add
是一个类型的函数,我称之为Adder
:
interface Adder {
(n: number): Adder;
(n?: undefined): number
}
Adder
是具有两个调用签名的重载函数;要么用number
调用它,在这种情况下会返回另一个Adder
,要么不带参数调用它(或者我猜是undefined
(,在这种情形下会得到number
。现在我们可以断言add
是Adder
:
const add = ((num?: number) => {
const adder = (n: number) => {
if (!n) {
return num;
}
num = (num && num + n) || n;
return adder;
};
return adder;
}) as Adder; // <-- assertion
然后一切如预期:
const result = add(1)(2)(3)() // no error now
console.log(result); // 6
游乐场链接到代码