【问题标题】:What AsyncGenerator TypeScript type yields a Promise?什么 AsyncGenerator TypeScript 类型会产生 Promise?
【发布时间】:2020-06-26 03:22:00
【问题描述】:

我正在尝试为以下函数分配返回类型:

async function *sleepyNumbers() {  // what TypeScript type is this?
  let n = 0;
  while (true) {
    yield new Promise(resolve => resolve(n++));
    await new Promise(resolve => setTimeout(resolve, 500));
  }
}

(async () => {
  for await (const i of sleepyNumbers())
    console.log(i);
})();

生成器正在生成一个解析为 number 的 Promise。将类型设置为 Promise<number> 失败并显示以下错误消息:

TS2739:“AsyncGenerator”类型缺少“Promise”类型的以下属性:then、catch、[Symbol.toStringTag]、finally

Iterable 导致了类似的错误。

我可以将类型设置为AsyncGenerator,但这还不够具体。该函数的返回类型的正确 TypeScript 语法是什么?

【问题讨论】:

    标签: typescript generator iterable


    【解决方案1】:

    它将是AsyncGenerator<number, never, void>

    number - next 结果
    never 返回
    void - next 没有得到任何参数

    您还需要显式键入一个 promise resolve:

    yield new Promise<number>(resolve => resolve(n++));

    大家一起:

    async function *sleepyNumbers(): AsyncGenerator<number, never, void> {
        let n = 0;
        while (true) {
            yield new Promise<number>(resolve => resolve(n++));
            await new Promise(resolve => setTimeout(resolve, 500));
        }
    }
    
    (async () => {
        for await (const i of sleepyNumbers())
            console.log(i);
    })();
    

    【讨论】:

    • 让 n = 0;产量 n++; while (true) yield new Promise(resolve => setTimeout(resolve, 500, n++));
    【解决方案2】:

    因为很多人看这里都需要一些退出条件,所以我将问题和Aleksey L.'s answer 调整为:

    1. 在 4 次迭代后停止:
    2. 修复生成的error TS2534: A function returning 'never' cannot have a reachable end point.(使用库“es2018.asyncgenerator”测试)。
    async function* sleepyNumbers(count: number): AsyncGenerator<number, void, void> {
      let n = 0;
      while (n < count) {
        yield new Promise<number>(resolve => resolve(n++));
        await new Promise(resolve => setTimeout(resolve, 250));
      }
    }
    
    (async () => {
      for await (const i of sleepyNumbers(4))
        console.log(i);
    })();
    

    #2 需要将第二个模板 arg 设置为 AsyncGeneratorvoid,因为生成器函数(function*)在没有返回的情况下落到最后,调用者返回:

    { value: undefined, done: true }
    

    调整生成器以在完成后传递一个最终值,我们看到了第二个模板参数的使用:

    async function* sleepyNumbers(count: number): AsyncGenerator<number, string, void> {
      let n = 0;
      while (n < count) {
        yield new Promise<number>(resolve => resolve(n++));
        await new Promise(resolve => setTimeout(resolve, 250));
      }
      return 'some string';
    }
    
    (async () => {
      const it = sleepyNumbers(4);
      let res;
      for (res = await it.next(); !res.done; res = await it.next())
        console.log(res);
      console.log('Finished with:', res);
      console.log('past end 1:', await it.next());
      console.log('past end 2:', await it.next());
    })();
    

    ,产生输出:

    { value: 0, done: false }
    { value: 1, done: false }
    { value: 2, done: false }
    { value: 3, done: false }
    Finished with: { value: 'some string', done: true }
    past end 1: { value: undefined, done: true }
    past end 2: { value: undefined, done: true }
    

    显然,在生成器完成后敲击迭代器总是会返回 value: undefined

    tldr;(好像这在 tldr-land 中还没有),我们一直在使用 AsyncGenerator 模板的 TReturn 参数:

    interface AsyncGenerator<T = unknown, TReturn = any, TNext = unknown> extends AsyncIterator<T, TReturn, TNext> {
        // NOTE: 'next' is defined using a tuple to ensure we report the correct assignability errors in all places.
        next(...args: [] | [TNext]): Promise<IteratorResult<T, TReturn>>;
        return(value: TReturn | PromiseLike<TReturn>): Promise<IteratorResult<T, TReturn>>;
        throw(e: any): Promise<IteratorResult<T, TReturn>>;
        [Symbol.asyncIterator](): AsyncGenerator<T, TReturn, TNext>;
    }
    

    (根据node_modules/typescript/lib/lib.es2018.asyncgenerator.d.ts),映射到TReturn in

    interface IteratorYieldResult<TYield> {
        done?: false;
        value: TYield;
    }
    
    interface IteratorReturnResult<TReturn> {
        done: true;
        value: TReturn;
    }
    
    type IteratorResult<T, TReturn = any> = IteratorYieldResult<T> | IteratorReturnResult<TReturn>;
    

    (根据 lib.es2015.iterable.d.ts)

    【讨论】:

      猜你喜欢
      • 2016-03-01
      • 2013-10-26
      • 1970-01-01
      • 2018-01-14
      • 2018-10-08
      • 2021-10-17
      • 1970-01-01
      相关资源
      最近更新 更多