打字稿:Typeguard Symbol.iterator

Typescript: Typeguard Symbol.iterator

我正在尝试编写一个接受 Iterable<T> 或 `AsyncIterable 并将其映射的函数:

function map<T, U>(
  fn: (item: T) => U,
  items: Iterable<T> | AsyncIterable<T>,
): Iterable<U> | Iterable<U> & AsyncIterable<U> {
  async function* asyncMapper() {
    for await (const item of items) {
      yield fn(item);
    }
  }

  if (!items[Symbol.iterator]) {
    return asyncMapper()
  }

  return {
    *[Symbol.iterator]() {
      for (const item of items) {
        yield fn(item);
      }
    },

    [Symbol.asyncIterator]: asyncMapper,
  };
}

See playground

它的要点是,如果项目实现 Symbol.iterator 我们将 return 一个可以同步迭代 异步的可迭代对象。但是,如果我们不这样做,我们将 return 只有异步迭代器。

问题是我无法对 Symbol.iterator 的存在进行类型保护,因为错误:

error TS7053: Element implicitly has an any type because expression of type symbol can't be used to index type Iterable<T> | AsyncIterable<T>.

有谁知道如何打字 Symbol.iterator,或者如果我在这里做错了什么?

使用用户定义的类型保护:

function isIterable(x: any): x is Iterable<unknown> {
  return Symbol.iterator in x;
}

function map<T, U>(
  fn: (item: T) => U,
  items: Iterable<T> | AsyncIterable<T>
): Iterable<U> | AsyncIterable<U> {
  async function* asyncMapper() {
    for await (const item of items) {
      yield fn(item);
    }
  }

  if (!isIterable(items)) {
    return asyncMapper()
  }

  return {
    *[Symbol.iterator]() {
      for (const item of items) {
        yield fn(item);
      }
    },

    [Symbol.asyncIterator]: asyncMapper,
  };
}

Playground link