【问题标题】:Type inference in TypeScript for curried functionTypeScript 中用于 curried 函数的类型推断
【发布时间】:2016-03-13 20:30:53
【问题描述】:

我对 TypeScript 中的柯里化函数有以下定义:

interface Curried2<A, B, Z> {
    (_0: A): (_0: B) => Z;
    (_0: A, _1: B): Z;
}

我有以下函数应该接受一个函数(curried 与否):

function apply<T, U>(f: (_0: T) => U, x: T): U {
    return f(x);
}

现在,给定

let curried: Curried2<number, boolean, string> = ...

以下作品(如预期):

apply<number, (_0: boolean) => string>(curried, 4);

但 TypeScript 无法自行推断类型:

apply(curried, 4);

(即使() 只有一个重载,它采用单个值。)它抱怨:

'Curried2' 类型的参数不可分配给'(_0: number) => string' 类型的参数...
它已经正确推断出T,但推断出Ustring。为什么是这样?在这种情况下,我该怎么做才能使类型推断对我有用(因为明确指定 TU 对于我的口味来说太冗长了)?

提前致谢!

【问题讨论】:

    标签: typescript type-inference


    【解决方案1】:

    以下现在有效:

    interface F1<A, Z> {
        (_0: A): Z;
    }
    
    interface F2<A, B, Z> extends F1<A, F1<B, Z>> {
        (_0: A, _1: B): Z;
    }
    
    function apply<T, U>(f: F1<T, U>, x: T): U {
        return f(x);
    }
    
    function apply2<T, U, V>(f: F2<T, U, V>, x: T, y: U): V {
        return f(x, y);
    }
    
    let curried: F2<number, boolean, string> = null;
    
    const x: F1<boolean, string> = apply(curried, 4);
    const y: string = apply2(curried, 4, false);
    

    【讨论】:

      【解决方案2】:

      我可以试试这个方法:

      type Curried<T1, T2, T3> = (x: T1) => (y: T2) => T3;
      
      function apply<T, U>(f: (value: T) => U, x: T): U {
          return f(x);
      }
      
      //simple demo
      var someFunc: Curried<string, number, [string, number]> = x => y => [x, y];
      var curriedSomeFunc = apply(someFunc, "string here");
      var result1 = curriedSomeFunc(0); //will be ["string here", 0]
      var result2 = curriedSomeFunc(1); //will be ["string here", 1]
      

      再试一次。如果您传递的不是正确的柯里化函数,语法是正确的,但不安全:

      interface Curried<T1, T2, T3> {
          (x: T1, y: T2): T3;
          (x: T1): (y: T2) => T3
      }
      
      let f1 = <Curried<string, number, [string, number]>>
          ((x: string, y: number) => [x, 1]);
      let f2 = <Curried<string, number, [string, number]>>
          ((x: string) => (y: number) => [x, y]);
      
      function apply<T, V>(f: (x: T) => V, x: T): V {
          return f(x);
      }
      
      let curriedF1 = apply(f1, "42"); //Won't work (no function to curry) but type inference is OK
      let curriedF2 = apply(f2, "11"); //Will work and type inference is also OK 
      

      【讨论】:

      • 在这种情况下,我将失去将该函数用作常规非curried函数的能力,因此不幸的是:(
      • 就是这样!您的示例(在哪种类型推断中有效)和我的示例(在哪种类型推断中无效)之间的唯一区别是Curried 的重载方法的顺序。知道这是为什么吗?
      • 现在下面的方法不再起作用了:function applyTwo&lt;S, T, V&gt;(f: (x: S, y: T) =&gt; V, x: S, y: T): V { return f(x, y); }; applyTwo(f1, "23", 23); 你认为这是什么原因?
      • 我认为对函数接口使用“重载”不是一个好习惯。它看起来更像是打字稿设计缺陷,而不是真正的功能。我更喜欢通过多个箭头表达式使用柯里化技术。
      猜你喜欢
      • 1970-01-01
      • 2020-02-16
      • 1970-01-01
      • 2018-08-28
      • 2020-09-09
      • 1970-01-01
      • 2019-12-09
      • 2021-11-24
      • 1970-01-01
      相关资源
      最近更新 更多