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

How to handle polymorphic type for both value and function?

考虑以下类型:

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

现在对于函数 apT 是一个 function,它的工作原理如下:

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

编写类型定义

这是一个棘手的问题!不能对所有 TTest<T> 的实例调用 ap() 方法,但仅当 T 是一个最多接受一个参数的函数时。

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

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() returns 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 :(