En pocas palabras
Biblioteca TypeScript para modelar efectos, errores, dependencias y concurrencia de forma componible.
Qué problema resuelve
Flujos asíncronos complejos con errores y limpieza de recursos difíciles de coordinar.
Cuándo utilizarlo
Servicios con integración y resiliencia. Ejemplo: consultar varias fuentes con timeout y política de reintento.
De la idea a la práctica
Funcionamiento, ejemplos y decisiones para pasar al siguiente nivel.
En el Radar compartido: Trial (valoración de la edición aportada).
Cómo funciona
Representa cálculos como valores que describen resultado, error y requisitos. La ejecución controla aspectos como cancelación, adquisición de recursos y composición.
Ejemplo de uso
Describir una consulta externa con error tipado y timeout. Aplicar reintentos solo a fallos transitorios y proporcionar una dependencia simulada para probar cada ruta.
El tipo Effect<A, E, R>
| Parámetro | Significado |
|---|---|
A |
Valor que produce si tiene éxito |
E |
Errores esperados, tipados |
R |
Dependencias (servicios) que necesita |
A diferencia de una Promise, un Effect es una descripción perezosa: no se ejecuta hasta que se corre explícitamente, lo que permite componer reintentos, timeouts y dependencias antes de ejecutar.
Ejemplo: cliente del buró con errores, reintentos y dependencias
import { Context, Data, Effect, Layer, Schedule } from 'effect';
class BuroError extends Data.TaggedError('BuroError')<{ status: number }> {}
class Buro extends Context.Tag('Buro')<
Buro,
{ consultar: (documento: string) => Effect.Effect<Historial, BuroError> }
>() {}
const evaluar = (documento: string) =>
Effect.gen(function* () {
const buro = yield* Buro;
const historial = yield* buro.consultar(documento);
return calcularPuntaje(historial);
}).pipe(
Effect.timeout('3 seconds'),
Effect.retry({
schedule: Schedule.exponential('200 millis'),
times: 2,
while: (e) => e._tag === 'BuroError' && e.status >= 500,
}),
Effect.catchTag('TimeoutException', () =>
Effect.succeed(PUNTAJE_PENDIENTE),
),
);
const BuroHttp = Layer.succeed(Buro, {
consultar: (doc) => llamarApiBuro(doc),
});
Effect.runPromise(evaluar('123456').pipe(Effect.provide(BuroHttp)));
El tipo de evaluar indica, sin leer la implementación, que puede fallar con BuroError y que necesita un Buro. En las pruebas se proporciona otra Layer con un buró simulado.
Ecosistema
| Módulo | Para qué |
|---|---|
Schema |
Validación y transformación de datos con tipos inferidos |
Stream |
Flujos de datos con control de recursos y backpressure |
Fiber |
Concurrencia estructurada con cancelación |
@effect/platform |
HTTP, sistema de archivos, terminal, multiplataforma |
@effect/sql |
Acceso a bases de datos |
@effect/opentelemetry |
Trazas automáticas de cada efecto |
Adopción gradual
- Empieza en el borde con más fallos: integraciones externas con reintentos y timeouts.
- Mantén una frontera clara: funciones que devuelven
Promisehacia el resto del código (Effect.runPromise). - Forma al equipo con ejemplos internos; la curva de aprendizaje es real.
- Amplía a otros módulos si los beneficios (errores explícitos, testabilidad) compensan.
Para equipos que solo necesitan validación, Zod o Schema por separado pueden bastar; Effect compensa cuando la complejidad está en la orquestación de efectos y errores. Ver patrones de resiliencia.
Criterios de implementación
Evitar reintentar operaciones no idempotentes sin protección. Definir fronteras con código Promise existente y revisar propagación de errores y finalización de recursos.
Continúa en las fuentes
Documentación oficial para verificar detalles y explorar más.