似乎在命名function()
语法与非同义函数语法的类型解除之间存在细微差别:
type F<X, Y> = (x: X) => Y
// works:
function apply<X, Y>(f: F<X, Y>, x: X) : Y {
return f(x)
}
// works:
const apply0 : <X, Y>(f: F, x: X) => Y = (f, x) => f(x)
// doesn't work
const apply1 : <X, Y>(f: F<X, Y>, x: X) => Y = (f, x) => f(x)
我需要在匿名F<X, Y>
函数的参数中对类型apply
的任何引用中删除泛型类型注释,以使类型检查器起作用。
这是违反直觉的。
[编辑:]但似乎Flow能够键入check apply1
调用,即使它无法键入check apply1
本身:
apply1(x => x * 2, 'a') // error: ^ string. This type is incompatible with
apply1(x => x * 2, 1) // works
更一般地说:
// works:
type Apply<X, Y> = <X, Y>(f: F, x: X) => Y
const apply : Apply = (f, x) => f(x)
// doesn't work:
type Apply1<X, Y> = <X, Y>(f: F<X, Y>, x: X) => Y
const apply1 : Apply1 = (f, x) => f(x)
我必须从类型别名X, Y
的参数中删除泛型类型注释Apply
,以便Flow检查它。
这是预期的行为还是我错过了什么?
答案 0 :(得分:5)
const apply1 = <X, Y>(f: F<X, Y>, x: X): Y => f(x)
首先,正如评论中提到的@squint一样,没有类型参数的F
隐含意味着F<any, any>
,这就是apply0
在您的示例中有效的原因。
那么为什么apply1
有错误?嗯,这是因为Flow不会推断出泛型。所以当你写了
const apply1 : <X, Y>(f: F<X, Y>, x: X) => Y = (f, x) => f(x)
作业的右侧是
(f, x) => f(x)
和Flow无法推断此箭头函数是多态的。所以你可以像这样在RHS中添加类型参数:
const apply1 : <X, Y>(f: F<X, Y>, x: X) => Y = <X, Y>(f: F<X, Y>, x: X): Y => f(x)
这应该可以解决错误。但此时,左侧的类型注释不再是必需的。所以你可以将它简化为
const apply1 = <X, Y>(f: F<X, Y>, x: X): Y => f(x)
Avik Chaudhuri在similar stack overflow question上写了一个简短的解释,然后链接到similar answer on GitHub