【问题标题】: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 抱怨。

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

【问题讨论】:

    标签: javascript typescript types functional-programming typescript2.0


    【解决方案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 好点,我度过了一个漫长的夜晚,并没有过多考虑可能的用例。我也没有看到你已经在我面前发布了答案......
    猜你喜欢
    • 2022-01-16
    • 1970-01-01
    • 2022-11-19
    • 1970-01-01
    • 1970-01-01
    • 2023-02-01
    • 2022-07-21
    • 1970-01-01
    • 2020-06-06
    相关资源
    最近更新 更多