函数返回函数时TypeScript类型推断问题

时间:2017-09-10 15:34:46

标签: typescript type-inference ramda.js

我有以下示例函数(compose来自Ramda):

    declare function compose<V0, T1, T2>(fn1: (x: T1) => T2, fn0: (x0: V0) => T1): (x0: V0) => T2;

    interface User {
      id: number
    }

    function fn1(input: any): User {
      return {id: 1};
    }

    function fn2<I, O>(fn: (i: I) => O): (i: I) => O {
       return (data) => {
         try {
           return fn(data);
         } catch (e) {
           return undefined
         }
      };
    }

当我试图像这样使用它时:

compose(fn2(user => user.id), fn1);

TypeScript会抛出以下错误:

TS2339:Property 'id' does not exist on type '{}'.

有谁知道,我该怎么做才能帮助TypeScript推断user的正确类型?

当然,以下代码将起作用:

compose<any, User, number>(fn2(user => user.id), fn1);

2 个答案:

答案 0 :(得分:1)

看起来参数类型是从左到右解决的,因为您正在向任何函数编写任何函数,首先会出现该错误。看看这个类似但代码相反的代码:

declare function compose<V0, T1, T2>(fn0: (x0: V0) => T1, fn1: (x: T1) => T2,): (x0: V0) => T2;

interface User {
  id: number
}

function fn1(input: number): User {
  return {id: 1};
}

function fn2<I, O>(fn: (i: I) => O): (i: I) => O {
   return (data) => {
     try {
       return fn(data);
     } catch (e) {
       return undefined
     }
  };
}

compose(fn1, fn2(user => user.id));

它可以像你期望的那样工作。但必须改变作文定义。

修改

与Titian Cernicova的答案类似,您可以至少定义进入您的撰写链的第一个参数元素,如下所示:

declare function compose<T1 = any, T2 = any, V0 = any>(fn1: (x: T1) => T2, fn0: (x0: V0) => T1): (x0: V0) => T2;

interface User {
  id: number
}

function fn1(input: number): User {
  return {id: 1};
}

function fn2<I, O>(fn: (i: I) => O): (i: I) => O {
   return (data) => {
     try {
       return fn(data);
     } catch (e) {
       return undefined
     }
  };
}

compose<User>(fn2(user => user.id), fn1);

答案 1 :(得分:0)

您不必指定所有类型,但需要指定user参数类型才能生效。

compose(fn2((user: User) => user.id), fn1);

如果您不使用fn2类型推断可行,但根据fn2返回的所需值,确定fn2的参数必须是(user:User)=> number类型对于Typescript编译器来说有点太多了。

这有效:

compose((user) => user.id, fn1);