首页 > 解决方案 > 如何确保传递给高阶函数的泛型函数具有 void 返回类型?

问题描述

function higherOrderFunction<P extends any[], R>(anyFunction: (...a: P) => R) {
  return (...args: P) => {
    anyFunction(...args); // anyFunction = lowerOrderFunction
  };
}

function lowerOrderFunction(name: string) {
  return '';
}

const higherOrderFunctionWithLowerOrderFunction = higherOrderFunction(lowerOrderFunction);
higherOrderFunctionWithLowerOrderFunction('x');

如何保证anyFunction会有void类型

这必须用于传递给higherOrderFunction的泛型函数(泛型在这里表示“任何函数”),而不仅仅是lowerOrderFunction上面的示例足以添加:void

标签: typescript

解决方案


TypeScript 不希望您这样做,请参阅常见问题解答。返回非void值的函数可以在void需要返回函数的任何地方使用。在 TypeScript 中,void返回类型意味着“你不应该尝试使用这个函数的返回值”而不是“这个函数真的没有返回值”。所以对这个问题最传统的回答是你不需要强制执行这样的限制;如果anyFunction返回一个值,它将被忽略,这应该没问题。


如果你真的想改变规则以便 TypeScript 强制执行限制,你可以做的一件事是:

function higherOrderFunction<P extends any[]>(anyFunction: (...a: P) => undefined | void) {
  return (...args: P) => { anyFunction(...args); };
}

通过指定undefined | void您是说您将接受一个undefined返回值(应该没问题,对吧?)或其他不返回的函数(void在联合中使用似乎绕过了编译器的“任何值都可以”的逻辑):

higherOrderFunction(() => 1); // error, number is not undefined
higherOrderFunction(() => undefined); // okay
higherOrderFunction(() => console.log("this is void returning")); // okay

或者,如果您想让编译器拒绝甚至undefined返回函数,您可以使用推断返回类型的通用签名,然后使事情不起作用,除非它推断的类型是void

function higherOrderFunction<P extends any[], R>(
  anyFunction: (...a: P) => R & (void extends R ? void : never)
) {
  return (...args: P) => { anyFunction(...args); };
}

该类型(void extends R ? void : never)评估为voidif Ris voidnever否则。所以你会得到这种行为:

higherOrderFunction(() => 1); // error, number is not never
higherOrderFunction(() => undefined); // error, undefined is not never
higherOrderFunction(() => console.log("this is void returning")); // okay

这些方法“有效”,因为它们对示例用例实施了限制,但可能存在边缘情况。最明显的边缘情况是以下代码无关,higherOrderFunction也不会产生警告:

const thisIsAllowed: () => void = () => 1; // okay

毕竟,非 void-returning 函数可以分配给 void-returning 函数。现在编译器将thisIsAllowed其视为void-returning 函数;它已经忘记了一切1

因此,无论如何higherOrderFunction()定义以“要求”void返回,这里都不会出错:

higherOrderFunction(thisIsAllowed); // no error

根据您的用例,这可能会破坏您的交易。


我认为最好的做法可能是接受 TypeScript 的观点,即void返回类型意味着“忽略返回的任何值”而不是“不返回任何值”,然后继续前进。也许上面的规则弯曲方法仍然对你有用,但你不应该依赖它们来禁止返回值的函数。


好的,希望有帮助;祝你好运!

游乐场链接


推荐阅读