javascript - 是否可以流式输入一个返回另一个可能被柯里化的函数的函数?
问题描述
假设您有一个返回另一个函数的函数,并且返回的该函数可能会或可能不会被柯里化。这可以是流式的吗?我猜答案可能是否定的。
这是一个例子:
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)
对于此代码,flow 给出以下错误:
add(2, 3)
^ Cannot call `add` because no more than 1 argument is expected by function [1].
References:
3: return function add(x) {
^ [1]
本质上,flow 无法确定返回了哪种函数样式。也不能输入接收函数的变量,例如:
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
直到运行时才知道这一事实有关。
解决方案
While it's true that Flow doesn't know whether curried
is true or false, you're hitting a much more fundamental limitation than that. In flow, a union type x : A | B
doesn't mean that x is either A or B, and that Flow doesn't have enough information to distinguish them. It means that x has the type A | B
. The type A | B
can only be consumed in two ways:
- by passing it to something which can accept both an A and a B
- by passing it to something which can separate out an A from a B, such as an
if
statement
The distinction is subtle, but it gets clearer if you think about what the type checking algorithm is doing. First, Flow checks that the type annotation of your getAddFn
is correct. The function returns number => number => number
in one place, and (number, number) => number)
in another. Flow thus infers the the type (number => number => number) | ((number, number) => number)
for the function.
Then, Flow holds onto this type and completely forgets about the function body. This is what I mean by the distinction above; once Flow knows that a function returns a union type, it knows everything it wants to about that function, and won't revisit it. Given this and the first bullet point above, the errors hopefully start to make sense.
As an aside, hopefully one day this sort of thing will be possible if Flow ever gets proper support for intersection-typed functions. Intersection types are documented here, but there are open github issues on the fact that they don't work with functions, such as this one here. If they worked properly, then it might be possible to use them alongside Flow's literal types to implement something like this. The trick would be to overload the function's type to say that it is both a function from the literal value true
to something of type number => number => number
and a function from the literal value false
to something of type (number, number) => number
. Alas, we currently don't have the ability to do this, and it is unclear whether we ever will.
推荐阅读
- curl - 如何确认 curl_global_init() 已被调用?
- java - 有没有办法从不在同一个文件中的其他 Java 程序运行 Java 程序?
- php - 在刀片中使用 subDays() 后 URL 不会改变 - Laravel
- jetty - 是否可以使用两个端口运行具有单个连接器的 Jetty 服务器,一个使用相互身份验证,另一个不使用?
- java - 如何修复 Java 中的“Index 5 out of bound for length 5”错误
- conditional-statements - ModelMapper - 条件和提供者
- reactjs - 如何为 REACT JS 中的无状态函数代码编写 JEST 单元测试用例,如下所示:
- php - 如何将多项选择数据作为数组发布到mysql数据库表
- javascript - 在draft-js中选择后实体内的光标
- arrays - 如何使用分治法在二维数组中查找特定列