Funciones generadoras en TypeScript
Este artículo explica las funciones generadoras en TypeScript.
Puedes aprender desde los conceptos básicos de cómo usar funciones generadoras hasta ejemplos avanzados combinados con el procesamiento asíncrono, junto con muestras de código.
YouTube Video
Funciones generadoras
Las funciones generadoras en TypeScript proporcionan una funcionalidad similar a las funciones generadoras de JavaScript. Las funciones generadoras se definen utilizando function*
(una declaración de función con un asterisco) y son funciones especiales que pueden pausar y reanudar la ejecución, a diferencia de las funciones normales.
Cuando se llama a una función generadora, se devuelve un iterador, que genera valores uno a la vez a través de este iterador, y se puede pausar la ejecución utilizando la palabra clave yield
o enviar valores desde el exterior.
Sintaxis básica de las funciones generadoras
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)
- Define una función generadora con
function* myGenerator()
. - La palabra clave
yield
pausa la ejecución de la función mientras devuelve un valor. - Cada vez que se llama al método
next()
, la ejecución de la función generadora se reanuda y avanza al siguienteyield
.
next()
devuelve un objeto que contiene el siguiente valor y una propiedad done
. Cuando done
es true
, indica que se han generado todos los valores y que el procesamiento del generador está completo.
Aplicaciones de las funciones generadoras
El uso de funciones generadoras permite una representación sencilla del procesamiento secuencial. En el siguiente ejemplo, se crea una función generadora que genera una secuencia 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
- En este ejemplo,
sequenceGenerator
genera una secuencia de números que aumenta indefinidamente. Usayield
para devolver valores en cada paso y genera el siguiente valor en llamadas posteriores.
Pasar valores a next
El método next()
puede recibir un valor, que puede enviarse a la función generadora.
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
- En este ejemplo,
next(5)
ynext(10)
envían sus respectivos valores a la función generadora, yyield num1 + num2
devuelve su suma.
return
y throw
return(value)
puede terminar el generador y devolver el valor especificado.throw(error)
puede lanzar una excepción dentro del generador, que se usa para manejar excepciones dentro del generador.
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!
- En este ejemplo, el método
throw
se usa para generar un error dentro del generador, y ese error se captura dentro del generador.
Definición de tipos en TypeScript
La definición de tipo de una función generadora se puede especificar en el siguiente formato.
1// Generator<YieldType, ReturnType, NextType>
2function* myGenerator(): Generator<number, void, unknown> {
3 yield 1;
4 yield 2;
5 yield 3;
6}
- Especificas los tipos en la forma de
Generator<YieldType, ReturnType, NextType>
.YieldType
es el tipo del valor devuelto poryield
.ReturnType
es el tipo del valor devuelto porreturn
.NextType
es el tipo del valor pasado anext()
.
En el siguiente ejemplo, se especifican tipos concretos para usar el generador de forma segura con 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)
Generadores y procesamiento asíncrono
Los generadores también se pueden utilizar para el procesamiento asíncrono. Por ejemplo, puedes usar yield
para esperar los resultados de operaciones asíncronas mientras continúas con el procesamiento secuencial. Sin embargo, en TypeScript o JavaScript, se usa más comúnmente async/await
.
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}
Por lo tanto, aunque puedes procesar operaciones asíncronas de forma secuencial con generadores, no se utilizan comúnmente para el procesamiento asíncrono porque Promesas y async
/await
son más convenientes.
Resumen
- Las funciones generadoras son funciones especiales definidas con
function*
que pueden devolver valores conyield
mientras se pausa la ejecución de la función. - Usa
next()
para reanudar el generador y recibir valores. Además, puedes enviar valores al generador usandonext(value)
. - Puedes usar
return()
ythrow()
para terminar funciones generadoras o manejar errores. - Al usar generadores en TypeScript, puedes utilizar definiciones de tipos para escribir código con tipos seguros.
Los generadores son herramientas poderosas que te permiten controlar la iteración de forma flexible.
Puedes seguir el artículo anterior utilizando Visual Studio Code en nuestro canal de YouTube. Por favor, también revisa nuestro canal de YouTube.