
Escuchar este post
Selecciona una voz y genera audio para escuchar este post
Una guía profesional para principiantes que quieren dominar la composición de generadores y efectos
Introducción
Si alguna vez te has encontrado con yield*
en código JavaScript o TypeScript y te has preguntado "¿qué demonios hace este asterisco?", estás en el lugar correcto. Este pequeño operador es una de las herramientas más elegantes pero menos comprendidas del lenguaje.
Parte 1: yield*
en JavaScript Nativo
¿Qué es un Generador?
Antes de entender yield*
, necesitamos claridad sobre los generadores. Un generador es una función especial que puede pausar su ejecución y reanudarla más tarde:
function* simpleGenerator() { console.log('Inicio'); yield 1; // Pausa aquí console.log('Medio'); yield 2; // Pausa de nuevo console.log('Fin'); return 3; } const gen = simpleGenerator(); console.log(gen.next()); // { value: 1, done: false } console.log(gen.next()); // { value: 2, done: false } console.log(gen.next()); // { value: 3, done: true }
La Magia de yield*
Ahora, imagina que tienes varios generadores y quieres combinarlos. Aquí es donde yield*
brilla:
function* generadorNumeros() { yield 1; yield 2; } function* generadorLetras() { yield 'A'; yield 'B'; } function* generadorCombinado() { yield* generadorNumeros(); // Delega a generadorNumeros yield* generadorLetras(); // Delega a generadorLetras yield 'Fin'; } // Uso: const resultado = [...generadorCombinado()]; console.log(resultado); // [1, 2, "A", "B", "Fin"]
Caso Práctico: Recorriendo un Árbol
Uno de los usos más elegantes de yield*
es recorrer estructuras anidadas:
class NodoArbol { constructor(valor, hijos = []) { this.valor = valor; this.hijos = hijos; } // Generador para recorrer el árbol en profundidad *recorrer() { yield this.valor; for (const hijo of this.hijos) { yield* hijo.recorrer(); // Delega recursivamente } } } const arbol = new NodoArbol(1, [ new NodoArbol(2, [new NodoArbol(4)]), new NodoArbol(3) ]); console.log([...arbol.recorrer()]); // [1, 2, 4, 3]
Parte 2: yield*
en Effect (TypeScript)
El Mundo de Effect
Effect es una biblioteca que trae programación funcional a TypeScript
. Usa Effect.gen
con generadores para manejar operaciones asíncronas de manera elegante.
La Diferencia Crucial
En Effect, yield*
no delega a otro generador, sino que aplana (flatten) un Effect que devuelve otro Effect:
import { Effect } from "effect" // ❌ Sin yield* (anidado y confuso) const operacionAnidada = Effect.gen(function* () { const innerEffect = Effect.succeed(42) const resultado = yield* innerEffect // resultado: number return resultado }) // ✅ Con yield* (limpio y directo) const operacionDirecta = Effect.gen(function* () { return yield* Effect.succeed(42) // resultado: number })
Ejemplo Práctico con Effect
Veamos un ejemplo más realista de cómo usar yield*
en una aplicación:
import { Effect } from "effect" // Simulamos operaciones asíncronas const obtenerUsuario = (id: string) => Effect.promise(() => fetch(`/api/usuarios/${id}`).then(res => res.json())) const validarPermisos = (usuario: any) => Effect.succeed(usuario.rol === 'admin') const obtenerDatosProtegidos = () => Effect.promise(() => fetch('/api/datos-protegidos').then(res => res.json())) // Flujo completo usando yield* const flujoAplicacion = Effect.gen(function* () { // Cada yield* espera el resultado y lo extrae automáticamente const usuario = yield* obtenerUsuario("123") const tienePermisos = yield* validarPermisos(usuario) if (!tienePermisos) { return { error: "Sin permisos" } } const datos = yield* obtenerDatosProtegidos() return { usuario, datos } }) // Ejecutar el efecto Effect.runPromise(flujoAplicacion) .then(resultado => console.log(resultado))
Beneficios Clave de yield*
en Effect
- Código más limpio: Evita el anidamiento complejo
- Tipado seguro: TypeScript infiere correctamente los tipos
- Manejo automático de errores: Los errores se propagan naturalmente
- Composición natural: Fácil de combinar múltiples operaciones
Comparación Visual
// ❌ Sin yield* - código anidado const ejemploAnidado = operacion1().pipe( Effect.flatMap(valor1 => operacion2(valor1)) ); // ✅ Con yield* - código secuencial const ejemploSecuencial = Effect.gen(function* () { const valor1 = yield* operacion1(); return yield* operacion2(valor1); });
Comparativa rápida
En JavaScript Nativo:
- Propósito: Delegar el control a otro generador.
- Resultado: Se consumen todos los valores del generador delegado antes de continuar.
En Effect (TypeScript):
- Propósito: Extraer el valor de un
Effect
anidado. - Resultado: Se obtiene el valor interno directamente, manteniendo el código plano y legible.
Mejores Prácticas
En JavaScript:
- Usa
yield*
para componer generadores complejos - Ideal para recorridos recursivos de estructuras
- Mantiene el código limpio y modular
En Effect:
- Siempre usa
yield*
con Effects dentro deEffect.gen
- Evita anidamiento innecesario
Mantiene la cadena de tipos intacta
- Propaga errores automáticamente
- Facilita la composición de operaciones
El operador yield*
es una herramienta poderosa que, dependiendo del contexto, puede delegar generación o aplanar estructuras. Dominarlo te permitirá escribir código más elegante, modular y mantenible.
Ya sea que estés construyendo generadores complejos en JavaScript puro o manejando efectos sofisticados en TypeScript, yield*
es tu aliado para la composición limpia de código.
¿Tienes preguntas sobre yield*
o quieres ver ejemplos más avanzados? ¡Únete a nuestra lista de correo!
Abrazo. Bliss. 🤓

20 años de Git
Checa este otro Post
