是否可以流式处理一个函数,该函数返回另一个可能被处理的函数?

时间:2018-07-11 23:11:05

标签: javascript types flowtype

假设您有一个返回另一个函数的函数,并且返回的那个函数可能会也可能不会被咖喱。可以输入流吗?我猜答案可能不是。

这是一个例子:

function getAddFn(curried) {
  if (curried === true) {
    return function add(x) {
      return function(y) {
        return x + y;
      }
    }
  }

  return function add(x, y) { return x + y };
}

const add = getAddFn(false);

add(2, 3)

对于此代码,流程产生以下错误:

add(2, 3)
           ^ Cannot call `add` because no more than 1 argument is expected by function [1].
References:
3:     return function add(x) {
              ^ [1]

从本质上讲,流程无法确定已返回哪种函数样式。也不可能键入接收函数的变量,例如:

const add: (number, number) => number = getAddFn(false);

在这种情况下,流程抱怨:

13: const add: (number, number) => number = getAddFn(false);
                                            ^ Cannot assign `getAddFn(...)` to `add` because function [1] is incompatible with number [2] in the return value.
References:
4:       return function(y) {
                ^ [1]
13: const add: (number, number) => number = getAddFn(false);
                                   ^ [2]

有人可以解释这是否可行吗?否则,请清楚说明原因?我可以看到问题可能与以下事实有关:传递给getAddFn的布尔值直到运行时才知道。

2 个答案:

答案 0 :(得分:1)

似乎流量不喜欢您的签名似乎是

num -> num | num -> num -> num

这意味着必须在运行时检查确切的类型。

答案 1 :(得分:1)

虽然Flow不知道curried是对还是假是对的,但您所遇到的基本限制远不止于此。在流中,联合类型x : A | B并不意味着x是A或B,并且Flow没有足够的信息来区分它们。这意味着x的类型为A | BA | B类型只能以两种方式使用:

  • 将其传递给可以接受 A 和 B
  • 的东西
  • 将其传递给可以将A与B分开的内容,例如if语句

区别是微妙的,但是如果您考虑类型检查算法的作用,它将变得更加清晰。首先,Flow检查您的getAddFn的类型注释正确。该函数在一个地方返回number => number => number,在另一个地方返回(number, number) => number)。因此,Flow会推断出函数的类型(number => number => number) | ((number, number) => number)

然后,Flow保持这种类型,并完全忘记了函数体。这就是我所说的区别。 Flow知道某个函数返回联合类型后,就知道该函数想要的所有信息,并且不会重新访问它。考虑到这一点和上面的第一个要点,这些错误有望开始变得有意义。


顺便说一句,希望有一天,如果Flow能够适当地支持交集类型的函数,那么这种事情将是可能的。交集类型已记录在here中,但是存在开放github问题,因为它们不能与诸如here这样的函数一起使用。如果它们正常工作,则可能可以将它们与Flow的literal types一起使用以实现类似的功能。诀窍是要重载该函数的类型,以使其既是从文字值true到类型number => number => number的函数,又是从文字值false到函数的某种函数。输入(number, number) => number。 las,我们目前尚无此能力,目前尚不清楚我们是否会这样做。