高阶函数返回泛型函数

时间:2018-04-10 03:29:24

标签: flowtype

所以在这个基本的例子中(tryflow):

// basic identity function example with generic type

type Foo = { prop: number};
type Bar = { prop: string };

const foo: Foo = { prop: 1 };
const bar: Bar = { prop: 'a' };

function identity<T>(same: T): T {
  return same;
}

// here identity acts as (Foo) => Foo
const foo2: Foo = identity(foo);

// and here it's (Bar) => Bar
const bar2: Bar = identity(bar);

我的identity函数,使用泛型,取任何类型的函数。由于参数与之绑定,T首先成为Foo,然后成为Bar

我想要的是一个返回泛型函数的高阶函数。我可以编写一个使用泛型(tryflow)的高阶函数:

type IdentityFunction = <T>(self: T) => T;

// error here
const baseId: IdentityFunction = (same) => same;
                                        // ^ Cannot assign function to 
                                        //   `baseId` because `T` [1] is 
                                        //   incompatible with `T` [2] in 
                                        //   the return value.

type Foo = { prop: number};
type Bar = { prop: string };

const foo: Foo = { prop: 1 };
const bar: Bar = { prop: 'a' };

function makeIdentity(func: IdentityFunction): IdentityFunction {
  return func;
}

const identity: IdentityFunction = makeIdentity(baseId);

const foo2: Foo = identity(foo);
const bar2: Bar = identity(bar);

对我来说,这种方法最有意义。老实说,我不确定为什么会收到这个错误。 T如何与自己不相容?是因为类型永远不会明确地应用于T吗?它在某种程度上是不确定的,所以它不能用于任何东西?但那么,这不是泛型的全部意义吗?无论如何,我确定我只是错过了类型系统的一些微妙之处,或者我可能会以错误的方式解决这个问题。任何帮助表示赞赏。

1 个答案:

答案 0 :(得分:1)

您需要一般性地键入您的baseID函数,以便Flow知道您期望的参数和返回类型。在尝试弄清楚真正做什么的baseId函数时,Flow似乎没有使用IndentityFunction的类型。

Try

type IdentityFunction = <T>(self: T) => T;

// no more error
const baseId: IdentityFunction = <S>(same: S): S => same;

type Foo = { prop: number};
type Bar = { prop: string };

const foo: Foo = { prop: 1 };
const bar: Bar = { prop: 'a' };

function makeIdentity(func: IdentityFunction): IdentityFunction {
  return func;
}

const identity: IdentityFunction = makeIdentity(baseId);

const foo2: Foo = identity(foo);
const bar2: Bar = identity(bar);

您可以将baseId的实例化简化为:

const baseId = <S>(same: S): S => same;

然后流动still understands这里发生了什么。

这种行为有点令人困惑,我想知道是否有充分的理由。你会认为它可以采取左侧的内容并将其应用于右侧的功能(特别是在像这样的简单情况下)。也许它与流程如何看待正确的表达有关?如果有其他人有想法,我很乐意听到。

无论哪种方式,我倾向于避免在声明的左侧声明函数的类型。不作为规则,我很少想在函数本身之外的某处声明函数的类型。