3 votes

Quel type TypeScript AsyncGenerator produit une Promise ?

J'essaie d'attribuer un type de retour à la fonction ci-dessous :

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);
})();

Le générateur génère une Promise qui se résout en une number . Régler le type sur Promise<number> échoue avec ce message d'erreur :

TS2739 : Il manque au type 'AsyncGenerator' les propriétés suivantes du type 'Promise' : then, catch, [Symbol.toStringTag], finally

Iterable a donné lieu à une erreur similaire.

Je peux définir le type à AsyncGenerator mais ce n'est pas assez précis. Quelle est la syntaxe TypeScript appropriée pour le type de retour de cette fonction ?

6voto

Aleksey L. Points 10476

Il sera AsyncGenerator<number, never, void> :

number - next resultado
never renvoie à
void - next ne reçoit pas de paramètre

Vous devrez également saisir explicitement une promesse de résolution :

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

Tous ensemble :

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);
})();

3voto

ericP Points 648

Étant donné que de nombreuses personnes cherchant ici auront besoin d'une condition de sortie, j'ai modifié la question et La réponse d'Aleksey L. à :

  1. le faire s'arrêter après 4 itérations :
  2. fixer le résultat error TS2534: A function returning 'never' cannot have a reachable end point. (testé en utilisant la librairie "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 a nécessité de rendre le 2ème modèle arg à AsyncGenerator être void car la fonction de générateur (le function* ) tombe à la fin sans retour et l'appelant récupère :

{ value: undefined, done: true }

En modifiant le générateur pour qu'il transmette une valeur finale une fois terminé, nous voyons l'utilisation du deuxième paramètre du modèle :

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());
})();

en produisant la sortie :

{ 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 }

Apparemment, taper sur un itérateur après que le générateur ait terminé revient toujours avec value: undefined .

tldr ; (comme si cela n'existait pas déjà au pays des tldr), nous avons joué avec l'outil TReturn du modèle AsyncGenerator :

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>;
}

(par node_modules/typescript/lib/lib.es2018.asyncgenerator.d.ts ), qui correspond à TReturn sur

interface IteratorYieldResult<TYield> {
    done?: false;
    value: TYield;
}

interface IteratorReturnResult<TReturn> {
    done: true;
    value: TReturn;
}

type IteratorResult<T, TReturn = any> = IteratorYieldResult<T> | IteratorReturnResult<TReturn>;

(par lib.es2015.iterable.d.ts)

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X