如何处理值和函数的多态类型?

时间:2016-09-15 22:00:24

标签: flowtype

考虑以下类型:

declare class Test<T> {
  static of(value: T): Test<T>;
  map<U>(fn: (value:T) => U): Test<U>;
}

现在,对于功能apTfunction,它的工作方式如下:

Test.of(x => x * 2)
    .ap(Test.of(5))
    .map(console.log) // Output(number): 10

Test.of(x => `${x * 2}!`)
    .ap(Test.of(5))
    .map(console.log) // Output(string): 10!

因此,要正确键入支票ap,我需要执行ap(Test<[get type of x]>): [type of output of T]

我尝试了Test<I, O>,其中I对于值是可选的。但是,它为其他功能增加了许多不必要的东西。有没有更好的方法来解决这个问题?

注意:我正在尝试为data.task

编写类型定义

1 个答案:

答案 0 :(得分:2)

这是一个棘手的问题!对于所有ap()Test<T>的{​​{1}}实例不能调用T方法,但仅当T是一个最多只能获得一个参数的函数时。{ / p>

所以你真正需要的东西仍然是TODO for Flow。它看起来像这样:

declare class Test<T> {
  static of(value: T): Test<T>;
  map<U>(fn: (value:T) => U): Test<U>;
  ap<I,O>(this: Test<(in: I) => O>, test: Test<I>): Test<O>;
}

它声明this必须是Test<T>T是一个I的函数。 Here's a GitHub issue about it

与此同时,您可以进行一阶近似。它看起来像这样:

declare class Test<T> {
  static of<I, O>(fn: (in: I) => O): FuncTest<I, O>;
  static of(value: T): Test<T>;

  map<U>(fn: (value:T) => U): Test<U>;
}

declare class FuncTest<I, O> extends Test<(in: I) => O> {
  ap(x: Test<I>): Test<O>;
}

Test.of(x => x * 2)
    .ap(Test.of(5))
    .map(x => (x: number)) // no error

Test.of(x => `${x * 2}!`)
    .ap(Test.of(5))
    .map(x => (x: string)) // no error

Try this example on flowtype.org/try

这种方法的缺点是ap()返回Test<O>,即使O是函数。所以你不能两次打电话给ap()

Test.of(x => Test.of(y => x * y))
  .ap(Test.of(5))
  .map(x => (x: Test<(y: number) => number>)); // This is fine

Test.of(x => Test.of(y => x * y))
  .ap(Test.of(5))
  .ap(Test.of(2)) // This is an error :(