javascript - 如何在 typescript 中输入 3 参数柯里化(Currying)函数?

标签 javascript typescript iterator currying

或者如何为返回的函数定义多个签名

我正在尝试创建一个柯里化(Currying)函数,但我在定义重载方面遇到了问题。具体来说,如果您调用parallelMap使用一个参数,您可以使用 1 个或 2 个参数调用下一个参数。但是 def 被标记为无效。

[ts] Overload signature is not compatible with function implementation. [2394]

export function parallelMap<T, R> (concurrency: number): (func: (data: T) => R | Promise<R>) => (iterable: AnyIterable<T>) => AsyncIterableIterator<R>

全面实现;

export function parallelMap<T, R> (concurrency: number): (func: (data: T) => R | Promise<R>, iterable: AnyIterable<T>) => AsyncIterableIterator<R>
export function parallelMap<T, R> (concurrency: number): (func: (data: T) => R | Promise<R>) => (iterable: AnyIterable<T>) => AsyncIterableIterator<R>
export function parallelMap<T, R> (concurrency: number, func: (data: T) => R | Promise<R>): (iterable: AnyIterable<T>) => AsyncIterableIterator<R>
export function parallelMap<T, R> (concurrency: number, func: (data: T) => R | Promise<R>, iterable: AnyIterable<T>): AsyncIterableIterator<R>
export function parallelMap<T, R> (
  concurrency: number,
  func?: (data: T) => R | Promise<R>,
  iterable?: AnyIterable<T>,
) {
  if (func === undefined) {
    return <A, B>(curriedFunc: (data: A) => B | Promise<B>, curriedIterable?: AnyIterable<A>) => parallelMap(concurrency, curriedFunc, curriedIterable)
  }
  if (iterable === undefined) {
    return (curriedIterable: AnyIterable<T>) => parallelMap<T, R>(concurrency, func, curriedIterable)
  }
  return _parallelMap<T, R>(concurrency, func, iterable)
}

谢谢!

最佳答案

Overloads当不同的参数类型应导致不同的返回类型时很有用。具有相同参数类型的两个不同重载签名是没有用的。这是因为,正如手册所说:

[The compiler] looks at the overload list, and proceeding with the first overload attempts to call the function with the provided parameters. If it finds a match, it picks this overload as the correct overload.

前两个重载具有相同的参数类型,因此第二个重载永远不会被使用。这意味着如果您调用 parallelMap()如果只有一个参数,它将返回一个有两个参数的函数,仅此而已。它不返回单参数函数。

让我们来解决这个问题。这里的解决方案是当您调用parallelMap()时对于一个参数,您希望返回一个重载函数,而不是只有一个参数或只有两个参数的函数。

此外,您希望泛型类型参数位于返回的函数上,因为当您调用 parallelMap(concurrency) 时那时你不知道什么TR最终将成为。

因此将前两个签名替换为:

export function parallelMap(concurrency: number): { 
  <T,R>(func: (data: T) => R | Promise<R>, iterable: AnyIterable<T>): AsyncIterableIterator<R>, 
  <T,R>(func: (data: T) => R | Promise<R>): (iterable: AnyIterable<T>) => AsyncIterableIterator<R> 
}

现在说“如果你用一个参数调用parallelMap(),它将返回另一个函数,可以用两个类型为XXX和YYY的参数调用并返回ZZZ,也可以用一个类型为XXX的参数调用并返回一个从 YYY 到 ZZZ 的函数。”

现在应该基本上可以工作了。请注意,由于您使用的是重载,因此以下代码并不完全正确:

  if (func === undefined) {
    return <A, B>(
      curriedFunc: (data: A) => B | Promise<B>, 
      curriedIterable?: AnyIterable<A>
    ) => parallelMap(concurrency, curriedFunc, curriedIterable) // error!
  }

毕竟,没有一个重载调用签名接受可能的 undefined第三个论点。您可以使用两个或三个定义的参数来调用它。所以你应该将其更改为:

  if (func === undefined) {
    return <A, B>(
      curriedFunc: (data: A) => B | Promise<B>,
      curriedIterable?: AnyIterable<A>
    ) => curriedIterable ?
        parallelMap(concurrency, curriedFunc, curriedIterable) :
        parallelMap(concurrency, curriedFunc)
  }

它调用 parallelMap() 的两个不同重载取决于是否curriedIterable已定义。

好的,希望有帮助。祝你好运!

关于javascript - 如何在 typescript 中输入 3 参数柯里化(Currying)函数?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53310509/

相关文章:

javascript - 如何判断websocket onmessage参数的类型?

Angular 5 Universal 在服务器端渲染期间等待 http 请求返回

java - 迭代器不循环

c++ - 如何实现 STL 风格的迭代器并避免常见的陷阱?

javascript - 使用elasticsearch按字母顺序排序

javascript - ckeditor替换word如何添加更多?

javascript - 奇怪的 html textarea 错误

angular - 如何从指令行为中排除特殊情况?

javascript - 运算符 '+' 不能应用于类型 'number[]' : How could I correct the build error?

C# - 将 2 个列表与自定义元素进行比较