Construire des applications IA fiables en TypeScript implique de gérer une multitude de préoccupations transversales : reprises lorsqu'un fournisseur LLM renvoie 429, délais d'attente quand un modèle prend trop de temps, concurrence structurée pour les appels d'outils en parallèle, et dégradation gracieuse lorsque des services en aval échouent. La plupart des équipes utilisent des promesses, des blocs try/catch et des bibliothèques de reprise improvisées, puis voient leur gestion d'erreurs se transformer en spaghetti à mesure que la boucle de l'agent grandit.
Effect-TS propose un modèle différent. Il s'agit d'une bibliothèque de programmation fonctionnelle pour TypeScript qui traite chaque opération comme un Effect typé et composable — capturant non seulement le type de succès, mais aussi la forme complète des erreurs, les dépendances requises et la durée de vie des ressources. Pour les applications IA où la fiabilité compte, Effect devient l'alternative de qualité production à async/await.
Qu'est-ce que Effect-TS
Effect (anciennement Effect-TS) est une bibliothèque TypeScript inspirée de ZIO de Scala et Cats Effect. Au lieu de représenter le travail asynchrone comme une Promise de T, vous le décrivez comme un Effect avec trois paramètres de type : valeur de succès, canal d'erreur et services requis.
Crucialement, un Effect est une description du travail, et non un travail en cours. Rien ne s'exécute tant que vous ne le lancez pas, ce qui signifie que vous pouvez composer, réessayer, temporiser, paralléliser et instrumenter votre code sans laisser fuiter ces préoccupations dans la logique métier.
Pourquoi c'est important pour les applications IA
Les applications IA modernes sont essentiellement des systèmes distribués compressés dans un seul processus. Un seul tour de conversation peut :
- Appeler un fournisseur LLM avec streaming
- Analyser et valider la sortie structurée
- Dispatcher vers un ou plusieurs outils (recherche web, base de données, fichiers)
- Agréger les résultats et les renvoyer au modèle
- Émettre la télémétrie et persister l'état de la conversation
Chaque étape peut échouer, expirer ou nécessiter une reprise. Avec async/await, vous finissez soit par ignorer les échecs, soit par envelopper chaque appel dans des helpers personnalisés. Effect intègre ces patterns dans le système de types.
import { Effect, Schedule, Duration } from "effect"
const callModel = (prompt: string) =>
Effect.tryPromise({
try: () => anthropic.messages.create({
model: "claude-opus-4-7",
messages: [{ role: "user", content: prompt }]
}),
catch: (e) => new ModelError({ cause: e })
}).pipe(
Effect.timeout(Duration.seconds(30)),
Effect.retry(
Schedule.exponential(Duration.seconds(1)).pipe(
Schedule.compose(Schedule.recurs(3))
)
)
)La politique de reprise, le timeout et le type d'erreur sont tous visibles au site d'appel. Vous pouvez les extraire dans un helper withResilience sans toucher à l'appel.
Services et injection de dépendances
Effect dispose d'un système d'injection de dépendances intégré basé sur des tags. Vous déclarez une interface de service, et Effect la propage à travers le type de votre calcul jusqu'à ce qu'elle soit fournie en bordure.
import { Context, Effect, Layer } from "effect"
class LLMProvider extends Context.Tag("LLMProvider")<
LLMProvider,
{ complete: (prompt: string) => Effect.Effect<string, ModelError> }
>() {}
const summarize = (text: string) =>
Effect.gen(function* () {
const llm = yield* LLMProvider
return yield* llm.complete(`Résumer : ${text}`)
})
const ClaudeLive = Layer.succeed(LLMProvider, {
complete: (p) => callModel(p).pipe(Effect.map((r) => r.content[0].text))
})Remplacer le fournisseur Claude réel par un mock pendant les tests est un changement d'une ligne. Pas de monkey-patching, pas d'état global, pas de gymnastique de mocking de modules.
Concurrence structurée pour les appels d'outils
Lorsqu'un agent dispatche des appels d'outils en parallèle — récupérer des données depuis trois API, scanner plusieurs fichiers, interroger plusieurs bases de données — les primitives de concurrence structurée d'Effect empêchent les tâches incontrôlées.
import { Effect, Duration } from "effect"
const runTools = (calls: ToolCall[]) =>
Effect.forEach(calls, runOneTool, {
concurrency: 5,
batching: true
}).pipe(Effect.timeout(Duration.seconds(60)))Si le calcul parent est interrompu ou que le timeout se déclenche, chaque fiber enfant est automatiquement nettoyé. Pas de promesses orphelines qui se complètent silencieusement en arrière-plan.
Schema : une alternative à Zod conçue pour Effect
Effect intègre un module Schema pour la validation à l'exécution, similaire en esprit à Zod mais intégré au système de types Effect. Les échecs d'analyse deviennent des erreurs Effect typées, les schémas se composent avec les effets, et vous pouvez dériver à la fois des encodeurs et des décodeurs depuis la même définition.
import { Schema } from "effect"
const ToolCallSchema = Schema.Struct({
name: Schema.String,
arguments: Schema.Record({ key: Schema.String, value: Schema.Unknown })
})
const parseToolCall = Schema.decode(ToolCallSchema)Pour les équipes déjà investies dans Zod, Effect interopère proprement. Pour les nouveaux projets livrant des sorties structurées depuis des LLM, Schema est un choix naturel.
Quand choisir Effect
Effect a une véritable courbe d'apprentissage. Les générateurs, l'injection de dépendances par tags et la construction des Layers sont peu familiers pour les développeurs TypeScript habitués à Express et Next.js. Le retour sur investissement augmente avec la complexité de ce que vous construisez.
Choisissez Effect quand :
- Vous construisez un agent IA longue durée ou un service d'orchestration
- La fiabilité et l'observabilité sont des exigences de premier ordre
- Votre équipe est à l'aise avec les patterns de programmation fonctionnelle
- Vous avez besoin d'un contrôle granulaire sur la concurrence, les reprises et les timeouts
Restez sur async/await quand :
- Vous livrez un petit projet ou un prototype
- L'équipe découvre TypeScript ou la programmation fonctionnelle
- Le runtime est de courte durée (fonctions serverless faisant une seule chose)
Adoption en 2026
L'adoption d'Effect s'est accélérée en 2026 alors que de plus en plus d'équipes atteignent les limites opérationnelles de TypeScript asynchrone classique. Plusieurs startups IA-natives et plateformes établies ont publiquement écrit sur la migration de chemins critiques vers Effect pour la gestion d'erreurs typée et la concurrence structurée. Les mainteneurs livrent une ligne majeure stable, une documentation robuste et une communauté Discord qui rappelle l'écosystème Rust des débuts par son sérieux.
Pour les équipes construisant des systèmes agentiques sur Node, Effect est le framework que nous recommandons d'évaluer avant de passer à l'échelle au-delà d'un worker à but unique. Ce n'est pas une solution miracle, mais il vous donne les coutures pour rendre la fiabilité testable et explicite.
Premiers pas
npm install effectLa documentation officielle sur effect.website couvre l'API complète, avec des tutoriels pratiques pour serveurs HTTP, streaming, schémas et orchestration IA. Commencez par le type Effect basique, puis ajoutez Schema, Layer et Stream selon vos besoins.
Effect est ce que TypeScript a de plus proche d'un véritable runtime fonctionnel. Pour les applications IA livrées en 2026, c'est précisément le genre de fondation qui mérite d'investir.