TypeScript 无法正确推断函数的确定性返回类型
我有一些任意的 myCallback 函数
const myCallback = (param: number) => {
// doSomething
};
我正在尝试创建另一个函数,它可能会接收参数,也可能不会接收参数,并返回我的回调函数 myCallback,无论是绑定的还是未修改的:
const useMyCallback = (optionalParam?: number) => {
return optionalParam === undefined
? myCallback
: () => myCallback(optionalParam);
};
但无论我是否传入参数,myCallback 的返回值类型都是 (param: number) => void
const myCallback = (param: number) => {
// doSomething
};
const useMyCallback = (optionalParam?: number) => {
return optionalParam === undefined
? myCallback
: () => myCallback(optionalParam);
};
const unboundCallback = useMyCallback(); // typed (param: number) => void as expected
const boundCallback = useMyCallback(1); // typed (param: number) => void, expected () => void
有没有什么技巧可以在不对每个 useMyCallback 调用进行类型转换的情况下实现我想要的效果?
答案#1
这里有几件事正在发生。
首先,让我们想象你想调用这种类型:
type Fn = ((arg: number) => void ) | (() => void)
在 JavaScript 中,你总是可以调用一个参数多于所需的函数。但是 TypeScript 不允许你调用一个参数少于所需的函数。而这个类型可能是一个需要参数的函数。所以,这意味着调用这个函数的唯一类型安全的方法是提供一个参数。
这就是为什么 boundCallback 需要一个参数。
其次,Typescript 实际上并不会执行你的代码,因此你还没有做足够的工作让它知道省略参数会改变返回类型。我认为最好的方法是使用重载。
// Overload signatures
function useMyCallback(): typeof myCallback
function useMyCallback(optionalParam?: number): () => void
// Implementation
function useMyCallback(optionalParam?: number) {
return typeof optionalParam === 'undefined'
? myCallback
: () => myCallback(optionalParam);
};
这些重载告诉 TypeScript 某些参数模式具有某些返回类型。然后你的函数有一个实现,它接受参数的超集,并返回返回值的超集。
现在 TypeScript 可以推断出,当你使用不同的参数时,你会得到不同的返回值。
这样你就完全避免了我在这个答案开头提到的问题,因为返回类型永远不会是两种函数类型的联合。它只是一个单一的函数类型,会根据参数而变化。
现在这个有效了:
const unboundCallback = useMyCallback(); //-> (param: number) => void
unboundCallback(0)
const boundCallback = useMyCallback(1); //-> () => void
boundCallback()
操场
