Funções Geradoras no TypeScript

Funções Geradoras no TypeScript

Este artigo explica as funções geradoras no TypeScript.

Você pode aprender desde o básico de como usar funções geradoras até exemplos avançados combinados com processamento assíncrono, juntamente com exemplos de código.

YouTube Video

Funções Geradoras

As funções geradoras no TypeScript fornecem funcionalidade semelhante às funções geradoras do JavaScript. As funções geradoras são definidas usando function* (uma declaração de função com um asterisco) e são funções especiais que podem pausar e retomar a execução, diferentemente das funções normais.

Quando uma função geradora é chamada, um iterador é retornado, que gera valores um de cada vez através deste iterador, e você pode pausar a execução usando a palavra-chave yield ou enviar valores a partir de fora.

Sintaxe Básica das Funções Geradoras

 1function* myGenerator(): Generator<number, void, unknown> {
 2    yield 1;
 3    yield 2;
 4    yield 3;
 5}
 6
 7const gen = myGenerator();
 8
 9console.log(gen.next().value); // 1
10console.log(gen.next().value); // 2
11console.log(gen.next().value); // 3
12console.log(gen.next().done);  // true (Iteration finished)
  • Defina uma função geradora com function* myGenerator().
  • A palavra-chave yield pausa a execução da função ao retornar um valor.
  • Cada vez que o método next() é chamado, a execução da função geradora é retomada e avança para o próximo yield.

next() retorna um objeto contendo o próximo valor e uma propriedade done. Quando done é true, isso indica que todos os valores foram gerados e o processamento do gerador está completo.

Aplicações das Funções Geradoras

Usar funções geradoras permite uma representação fácil de processamento sequencial. No exemplo a seguir, criamos uma função geradora que gera uma sequência de números.

 1function* sequenceGenerator(start: number = 0, step: number = 1) {
 2    let current = start;
 3    while (true) {
 4        yield current;
 5        current += step;
 6    }
 7}
 8
 9const seq = sequenceGenerator(1, 2);
10
11console.log(seq.next().value); // 1
12console.log(seq.next().value); // 3
13console.log(seq.next().value); // 5
  • Neste exemplo, sequenceGenerator gera uma sequência indefinidamente crescente de números. Use yield para retornar valores em cada etapa e gere o próximo valor em chamadas subsequentes.

Passando Valores para next

O método next() pode receber um valor, que pode ser enviado para a função geradora.

 1function* adder() {
 2    const num1 = yield;
 3    const num2 = yield;
 4    yield num1 + num2;
 5}
 6
 7const addGen = adder();
 8addGen.next();          // Initialization
 9addGen.next(5);         // Set 5 to num1
10const result = addGen.next(10).value; // Set 10 to num2 and get result
11console.log(result);    // 15
  • Neste exemplo, next(5) e next(10) enviam seus respectivos valores para a função geradora, e yield num1 + num2 retorna a soma deles.

return e throw

  • return(value) pode finalizar o gerador e retornar o valor especificado.
  • throw(error) pode lançar uma exceção dentro do gerador, usado para tratar exceções dentro do gerador.
 1function* testGenerator() {
 2    try {
 3        yield 1;
 4        yield 2;
 5    } catch (e) {
 6        console.error("Error caught:", e);
 7    }
 8}
 9
10const gen = testGenerator();
11console.log(gen.next().value); // 1
12gen.throw(new Error("An error occurred!")); // Error caught: An error occurred!
  • Neste exemplo, o método throw é usado para gerar um erro dentro do gerador, e esse erro é capturado dentro do gerador.

Definição de Tipo em TypeScript

A definição de tipo de uma função geradora pode ser especificada no seguinte formato.

1// Generator<YieldType, ReturnType, NextType>
2function* myGenerator(): Generator<number, void, unknown> {
3    yield 1;
4    yield 2;
5    yield 3;
6}
  • Você especifica os tipos na forma de Generator<YieldType, ReturnType, NextType>.
    • YieldType é o tipo do valor retornado por yield.
    • ReturnType é o tipo do valor retornado por return.
    • NextType é o tipo do valor passado para next().

No exemplo a seguir, tipos específicos são especificados para usar o gerador de forma segura com tipos.

 1function* numberGenerator(): Generator<number, void, number> {
 2    const num1 = yield 1;
 3    const num2 = yield num1 + 2;
 4    yield num2 + 3;
 5}
 6
 7const gen = numberGenerator();
 8
 9console.log(gen.next().value);   // 1
10console.log(gen.next(10).value); // 12 (10 + 2)
11console.log(gen.next(20).value); // 23 (20 + 3)

Geradores e Processamento Assíncrono

Geradores também podem ser utilizados para processamento assíncrono. Por exemplo, você pode usar yield para aguardar os resultados de operações assíncronas enquanto continua o processamento sequencial. No entanto, em TypeScript ou JavaScript, async/await é mais comumente usado.

1function* asyncTask() {
2    const result1 = yield fetch("https://codesparklab.com/json/example1.json");
3    console.log(result1);
4
5    const result2 = yield fetch("https://codesparklab.com/json/example2.json");
6    console.log(result2);
7}

Assim, embora seja possível processar operações assíncronas sequencialmente com geradores, eles não são frequentemente usados para processamento assíncrono porque Promises e async/await são mais convenientes.

Resumo

  • Funções geradoras são funções especiais definidas com function* que podem retornar valores com yield enquanto pausam a execução da função.
  • Use next() para retomar o gerador e receber valores. Além disso, você pode enviar valores para o gerador usando next(value).
  • Você pode usar return() e throw() para terminar funções geradoras ou lidar com erros.
  • Ao usar geradores em TypeScript, você pode utilizar definições de tipo para escrever código com segurança de tipos.

Geradores são ferramentas poderosas que permitem controlar a iteração de forma flexível.

Você pode acompanhar o artigo acima usando o Visual Studio Code em nosso canal do YouTube. Por favor, confira também o canal do YouTube.

YouTube Video