返回作为参数提供的函数时保留类型签名

Posted

技术标签:

【中文标题】返回作为参数提供的函数时保留类型签名【英文标题】:Preserving type signature when returning a function that was supplied as a parameter 【发布时间】:2018-09-03 13:55:35 【问题描述】:

我有一个名为conditional 的函数,它接收一个布尔值和一个函数,如果布尔值为真则返回该函数,否则返回一个虚拟函数。

function conditional(x, f) 
  if(x)
    return f
  else
    return () => 

所以,我可以执行如下代码:

let mySqrt = conditional(true, Math.sqrt)
let add = (x, y) => x + y
let myAdd = conditional(true, add)

但是,当我向条件函数添加类型时,提供给conditional 函数的函数的类型签名会丢失。这使得编写 mySqrt("a") 这样的代码成为可能,而不会出现 TypeScript 抱怨。

如何向条件函数添加类型以保留结果函数的类型?

【问题讨论】:

【参考方案1】:

你需要使用泛型类型参数来表示函数的类型:

function conditional<T extends (...args: any[]) => any>(x: boolean, f: T): T 
    if (x)
        return f;
    else
        return (() =>  ) as any; // we need an assertion here to make the empty function compatible with T


// Usage
let mySqrt = conditional(true, Math.sqrt); //mySqrt will be of type (x: number) => number
let add = (x: number, y: number) => x + y;
let myAdd = conditional(true, add); // myAdd will be of type (x: number, y: number) => number

【讨论】:

虽然 Tao 的解决方案有效,但我发现这个解决方案更通用,更接近我的预期。谢谢!【参考方案2】:

您可以结合使用泛型和方法重载签名。

function conditional<T extends Function>(x: true, f: T): T;
function conditional<T extends Function>(x: false, f: T): () => ;
function conditional<T extends Function>(x: boolean, f: T) 
  if(x)
    return f
  else
    return () => 


let mySqrt = conditional(true, Math.sqrt)
mySqrt('a') // error

当提供重载方法签名时,编译器将隐藏实际的、更灵活的实现。

【讨论】:

虽然在参数常量上以不同的方式键入结果很好,但我认为在这种情况下,期望的结果是能够基于参数选择实现并让其余代码无缝工作的实施。您的实现将根据传入的常量破坏客户端代码,不确定这是意图,但 OP 应该权衡 @TitianCernicova-Dragomir 好点,我度过了一个漫长的夜晚,并没有过多考虑可能的用例。我也没有看到你已经在我面前发布了答案......

以上是关于返回作为参数提供的函数时保留类型签名的主要内容,如果未能解决你的问题,请参考以下文章

函数签名

规范函数签名的必要性

Python函数,它返回自己的带有参数的签名

Kotlin语法总结:函数类型和高阶函数

“通用类型系统”(CTS)

使用返回不完整类型的函数作为默认参数