El tipo Promise tiene un punto ciego en producción
Imagina un contrato común en tu base de código: Promise<User>. Este tipo describe perfectamente el camino feliz: esperas un objeto User si todo va bien. ¿Pero qué pasa con el mundo real? No dice nada sobre un error HTTP, un usuario no encontrado o una solicitud que se queda colgada indefinidamente, dejando a tu aplicación esperando.
TypeScript, desafortunadamente, no tipa de forma fiable los rechazos de promesas. Tus manejadores catch a menudo reciben un valor unknown, obligándote a adivinar en tiempo de ejecución qué salió mal. Esto significa que los equipos pierden un tiempo valioso estableciendo comportamientos ante fallos mediante prueba y error, no mediante comprobaciones robustas del compilador.
Considera un servicio que obtiene perfiles de usuario. Quienes lo llaman necesitan algo más que solo un User o un error sin tipo. Necesitan saber si deben reintentar la solicitud automáticamente (como ante un fallo de red transitorio), mostrar un mensaje claro de "usuario no encontrado" o dejar de esperar tras un tiempo de espera específico. Sin esta claridad en tus tipos, tu entorno de producción se convierte en un punto ciego, ocultando información crucial sobre por qué fallan las cosas.
Effect añade las partes que faltan al contrato
Effect cambia el contrato de Promise<User> a algo más robusto. Su firma principal es Effect<A, E, R>, que describe con precisión tres aspectos cruciales de cualquier computación: el valor de éxito, el fallo tipado y cualquier dependencia requerida.
Desglosemos esto. A representa el valor que obtienes al tener éxito, como User en nuestro ejemplo. E es donde ocurre la magia para los fallos, proporcionando una unión tipada de todos los errores esperados, como HttpError | NotFound. Finalmente, R significa "requisitos" (requirements): los servicios o dependencias que el código necesita para ejecutarse, como un cliente HTTP o una conexión a base de datos.
Considera nuestra función de búsqueda de usuario del vídeo. En lugar de solo Promise<User>, su tipo Effect podría ser Effect<User, HttpError | NotFound, SomeHttpClient>. Esto hace que el contrato sea explícito: te dice no solo que podrías obtener un User, sino también que un HttpError o una condición NotFound son modos de fallo específicos y esperados.
Esta es una gran diferencia con respecto a una promesa ordinaria. Las computaciones de Effect son valores perezosos (lazy values), lo que significa que describen qué hacer, pero no cuándo hacerlo. Compones toda tu computación, incluyendo reintentos, tiempos de espera y políticas de manejo de errores, antes de la ejecución. Esto mantiene todos los requisitos y resultados potenciales visibles mientras construyes tu programa, transformando un punto ciego en un mapa detallado.
Observa cómo cambia el tipo de error a medida que añades seguridad
Sigamos cómo evoluciona el tipo de error a medida que añadimos resiliencia a una tubería de obtención de datos. Inicialmente, nuestro Effect<User, HttpError | NotFound, R> puede fallar con un HttpError o un NotFound.
Primero, aplicamos una política de reintento exponencial para manejar los HttpErrors transitorios, pero esto no cambia la firma del tipo porque los reintentos no eliminan la posibilidad de un HttpError. A continuación, añadimos un tiempo de espera de dos segundos. Esto introduce inmediatamente TimeoutError en nuestro tipo de error, convirtiéndolo en Effect<User, HttpError | NotFound | TimeoutError, R>.
Luego, manejamos explícitamente el caso NotFound proporcionando un valor de reserva. Como por arte de magia, el tipo NotFound desaparece de nuestra firma de error porque ahora está garantizado que será manejado. Nuestro tipo se convierte en Effect<User, HttpError | TimeoutError, R>. Esto no es solo un truco inteligente; es el compilador realizando una contabilidad en tiempo real de los fallos potenciales.
Para probar esto, reducimos el tiempo de espera a solo 50 milisegundos. Al ejecutar el código, se produce un TimeoutError, exactamente como predijo el sistema de tipos. Este ciclo de retroalimentación en tiempo de compilación, verificado en tiempo de ejecución, es una característica poderosa de Effect: Production-Grade TypeScript y su enfoque para hacer que los fallos sean visibles y manejables.
¿Te está gustando? Recibe uno así en tu bandeja cada mañana.
un correo al día · date de baja en dos clics · sin rastreadores de terceros
La recompensa y el costo del cambio
El seguimiento explícito de errores y dependencias destaca en servicios críticos como la autenticación y los pagos. En estos ámbitos, las rutas de rechazo ocultas (como el tiempo de espera de una API externa o la caída de una conexión a la base de datos) hacen que la recuperación y la revisión sean mucho más difíciles. El enfoque basado en tipos de Effect garantiza que abordes estos posibles modos de fallo de forma proactiva, no reactiva.
Effect ofrece más que un tipo Result básico. Incluye un tiempo de ejecución robusto que proporciona herramientas para reintentos, tiempos de espera, concurrencia y gestión de dependencias desde el primer momento. En lugar de reemplazar instantáneamente tu código basado en Promise, Effect puede complementarlo, permitiendo una adopción e integración gradual en partes específicas y de alto valor de tu aplicación.
Adoptar Effect requiere una inversión de aprendizaje. El modelo, con su firma distintiva Effect<A, E, R>, requiere tiempo para comprenderse, especialmente cómo evolucionan los tipos de error a través de tu pipeline. A medida que los tipos de Effect se propagan naturalmente a través de los límites de la aplicación, los equipos deben sopesar cuidadosamente estos costos de aprendizaje y migración frente a los beneficios de una mayor fiabilidad y observabilidad, particularmente para sistemas sensibles.
Preguntas frecuentes
¿Qué es Effect en TypeScript?
Effect es una biblioteca para modelar programas asíncronos con valores de éxito explícitos, errores tipados y servicios requeridos.
¿En qué se diferencia Effect de una Promise?
Una Promise describe un valor que puede resolverse o rechazarse, pero no codifica los tipos de rechazo. Effect también modela fallos tipados y dependencias.
¿Cómo cambian los tipos de Effect cuando se maneja un error?
Manejar un error tipado elimina ese fallo del tipo de error del Effect; añadir una operación como un tiempo de espera puede añadir un nuevo fallo tipado.
¿Debería todo proyecto de TypeScript adoptar Effect?
No necesariamente. Puede ayudar a sistemas complejos que necesitan fallos explícitos y controles en tiempo de ejecución, pero sus conceptos y su huella en los tipos requieren una inversión de adopción.

