如何确保传递给高阶函数的泛型函数具有void返回类型?

时间:2020-08-16 23:33:14

标签: typescript

AWS

如何确保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类型

这必须是传递给HigherOrderFunction的泛型函数(此处泛指“任何函数”),而不仅仅是上面的示例void足以添加{{1} }

2 个答案:

答案 0 :(得分:4)

TypeScript不希望您执行此操作,请参见the FAQ。无论何时需要返回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)void,则类型R的值为void,否则为never。这样您就会得到以下行为:

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

毕竟,非无效返回函数可以分配给无效返回函数。现在,编译器将thisIsAllowed视为返回void的函数;它已经忘记了1

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

higherOrderFunction(thisIsAllowed); // no error

根据您的用例,这可能对您来说是个大难题。


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


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

Playground link

答案 1 :(得分:0)

只需更改传递给参数的anyFunction的返回类型

function higherOrderFunction<P extends any[], R>(anyFunction: (...a: P) => void) {
    return (...args: P) => {
      anyFunction(...args); // anyFunction = lowerOrderFunction
    };
  }
  
  function lowerOrderFunction(name: string) {
    return '';
  }
  
  const higherOrderFunctionWithLowerOrderFunction = higherOrderFunction(lowerOrderFunction);
  higherOrderFunctionWithLowerOrderFunction('x');