多态匿名函数类型别名

时间:2016-08-07 13:39:49

标签: javascript flowtype

似乎在命名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)

Flow console snippet

我需要在匿名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)

Flow console snippet

我必须从类型别名X, Y的参数中删除泛型类型注释Apply,以便Flow检查它。

这是预期的行为还是我错过了什么?

1 个答案:

答案 0 :(得分:5)

TL; DR:尝试

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