多态匿名函数类型别名

Polymorphic Anonymous Functions Type Aliases

本文关键字:类型 别名 函数 多态      更新时间:2023-09-26

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

流控制台代码段

我需要从匿名apply函数的参数中对类型F<X, Y>的任何引用中删除泛型类型注释,以便类型检查器工作。

这是违反直觉的

[编辑:]但似乎流量能够类型检查apply1调用,即使它无法类型检查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)

流控制台代码段

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

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

TL;DR: Try

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在一个类似的堆栈溢出问题上写了一个简短的解释,然后链接到GitHub上的一个类似的答案