Zygos
ζυγός - « balance »
Gestion fonctionnelle des erreurs. Alternatives légères à Neverthrow et fp-ts (Either, Task, TaskEither).
Zygos apporte les patterns de gestion fonctionnelle des erreurs à TypeScript sans le poids d'une bibliothèque FP complète. Au lieu de blocs try/catch qui perdent l'information de type, Zygos utilise les types Result, Option et Either pour rendre les erreurs explicites dans les signatures de vos fonctions. Chaque chemin d'échec est visible par le compilateur, vous gérez donc les erreurs avant qu'elles n'atteignent la production.
Quelques exemples
Le type Result représente une opération qui peut réussir (Ok) ou échouer (Err). Le pattern matching sur le résultat vous force à gérer les deux cas, éliminant les exceptions non gérées :
import { ok, err, Result } from "pithos/zygos/result/result";
function divide(a: number, b: number): Result<number, string> {
if (b === 0) return err("Division par zéro");
return ok(a / b);
}
const result = divide(10, 2);
if (result.isOk()) {
console.log(result.value); // 5
} else {
console.log(result.error); // Jamais atteint
}
Monades disponibles
| Monade | Description | Cas d'usage |
|---|---|---|
| Result | Ok<T> ou Err<E> | Opérations qui peuvent échouer |
| Option | Some<A> ou None | Valeurs optionnelles (pas de null) |
| Either | Left<E> ou Right<A> | Branchement générique à deux cas |
| Task | Calcul async paresseux | Opérations async différées |
| TaskEither | Either async | Opérations async qui peuvent échouer |
Result
Le Result de Zygos est 2.6x plus petit (~774 B vs ~1.96 kB) que Neverthrow, tout en maintenant une compatibilité API à 100%. Vous obtenez la même expérience développeur avec une fraction du coût en bundle.
Interchangeabilité avec Neverthrow
Pour migrer de Neverthrow vers Zygos, rien de plus simple : remplacez les imports et le tour est joué.
// Avant (Neverthrow)
import { ok, err, Result, ResultAsync } from "neverthrow";
// Après (Zygos) : changez uniquement l'import, le code reste IDENTIQUE
import { ok, err, Result } from "pithos/zygos/result/result";
import { ResultAsync } from "pithos/zygos/result/result-async";
// Votre code existant fonctionne sans changement
Rechercher & remplacer from "neverthrow" → séparer en les deux imports ci-dessus. Toutes les méthodes fonctionnent pareil.
Utilisation
Les Results supportent le chaînage avec map, mapErr et andThen. Chaque opération transforme la valeur de succès tout en propageant automatiquement les erreurs, similaire à la façon dont les Promises chaînent avec .then() :
import { ok, err, Result } from "pithos/zygos/result/result";
import { ResultAsync } from "pithos/zygos/result/result-async";
// Sync
const success = ok(42);
const failure = err("Quelque chose s'est mal passé");
// Le chaînage transforme la valeur Ok à travers chaque étape.
// Si une étape retourne un Err, la chaîne court-circuite.
ok(5)
.map(x => x * 2) // Ok(10)
.mapErr(e => `Erreur : ${e}`) // Toujours Ok(10)
.andThen(x => ok(x + 1)); // Ok(11)
// ResultAsync encapsule les Promises dans le même pattern Result,
// pour que les opérations async aient aussi une gestion d'erreurs typée.
const asyncResult = ResultAsync.fromPromise(
fetch("/api/data"),
() => "Erreur réseau"
);
Option
Gérez les valeurs optionnelles sans null/undefined. Le type Option rend l'absence de valeur explicite dans le système de types, remplaçant les types nullable par Some (valeur présente) ou None (valeur absente) :
import { some, none, fromNullable, Option, map, flatMap } from "pithos/zygos/option";
import { pipe } from "pithos/arkhe/function/pipe";
const value = some(42);
const empty = none;
// Depuis nullable
const maybeNull: string | null = "hello";
const opt = fromNullable(maybeNull); // Some("hello")
// Pattern matching
const result = isSome(opt)
? opt.value
: "default";
// Chaînage avec pipe
pipe(
some(5),
map(x => x * 2), // Some(10)
flatMap(x => some(x + 1)) // Some(11)
);
Either, Task, TaskEither
Implémentations légères basées sur fp-ts, 100% compatibles API. Ces monades couvrent des patterns de programmation fonctionnelle plus avancés : Either pour le branchement générique à deux cas, Task pour les calculs async paresseux, et TaskEither pour les opérations async qui peuvent échouer.
Interchangeabilité avec fp-ts
Migrer de fp-ts vers Zygos est tout aussi simple : remplacez les imports et c'est tout.
// Avant (fp-ts)
import * as E from "fp-ts/Either";
import * as T from "fp-ts/Task";
import * as TE from "fp-ts/TaskEither";
// Après (Zygos) : changez uniquement l'import, le code reste IDENTIQUE
import * as E from "pithos/zygos/either";
import * as T from "pithos/zygos/task";
import * as TE from "pithos/zygos/task-either";
// Votre code existant fonctionne sans changement
const result = pipe(
E.right(5),
E.map(x => x * 2),
E.flatMap(x => E.right(x + 1))
);
Rechercher & remplacer from "fp-ts/Either" → from "pithos/zygos/either", etc. Toutes les fonctions fonctionnent pareil.
Fonctions disponibles
| Module | Fonctions |
|---|---|
| Either | left, right, isLeft, isRight, map, mapLeft, flatMap, fold, match, getOrElse, orElse, fromOption, fromNullable, tryCatch, Do, bind, bindTo, apS |
| Task | of, map, flatMap, ap |
| TaskEither | left, right, tryCatch, fromEither, fromTask, fromOption, map, mapLeft, flatMap, chain, fold, match, getOrElse, orElse, swap |
safe() - Du try/catch au Result en une ligne
Permet d'encapsuler n'importe quelle fonction qui pourrait throw dans une fonction retournant un Result. C'est particulièrement utile pour les API tierces ou les fonctions natives comme JSON.parse qui communiquent les erreurs via des exceptions :
import { safe } from "pithos/zygos/safe";
const safeJsonParse = safe(JSON.parse);
const result = safeJsonParse('{"valid": true}');
// Ok({ valid: true })
const invalid = safeJsonParse('not json');
// Err(SyntaxError: ...)
Quand l'utiliser
Zygos brille dans les codebases où la gestion des erreurs doit être explicite et composable :
- Appels API →
ResultAsyncpour une gestion d'erreurs typée - Chaînes de validation →
ResultavecandThen - Données optionnelles →
Optionau lieu denull | undefined - Encapsuler du code unsafe →
safe()pour éliminer les try/catch
ensure() valide une donnée avec un schéma Kanon et retourne directement un Result<T, string> — prêt à chaîner avec map, andThen, etc. ensureAsync() fait la même chose pour les pipelines async avec ResultAsync, et ensurePromise() combine une Promise et la validation en un seul appel. Voir Alchimie des modules pour d'autres combinaisons.
Quand NE PAS l'utiliser
Pour des tâches en dehors de la gestion des erreurs et du flux de contrôle, d'autres modules Pithos sont plus appropriés :
Migrer depuis Neverthrow ou fp-ts
Depuis Neverthrow
Étape 1 : Installer
Ajoutez Pithos à votre projet. Il inclut Zygos et tous les autres modules :
- npm
- pnpm
- yarn
- bun
npm install @pithos/core
pnpm install @pithos/core
yarn add @pithos/core
bun add @pithos/core
Étape 2 : Mettre à jour les imports
// Avant
import { ok, err, Result, ResultAsync, safeTry } from "neverthrow";
// Après
import { ok, err, Result, safeTry } from "pithos/zygos/result/result";
import { ResultAsync } from "pithos/zygos/result/result-async";
Étape 3 : Exécuter vos tests
Tout votre code existant fonctionne tel quel. L'API est 100% compatible.
Étape 4 (optionnel) : Utiliser les fonctionnalités supplémentaires
Une fois migré, vous pouvez profiter des fonctionnalités spécifiques à Zygos :
// Ponts fp-ts
import { fromOption, fromEither, toEither } from "pithos/zygos/result/result";
// Try async simplifié
import { safeAsyncTry } from "pithos/zygos/result/result";
// Collecter toutes les erreurs
const allErrors = ResultAsync.combineWithAllErrors(results);
Depuis fp-ts
Étape 1 : Installer
Ajoutez Pithos à votre projet. Il inclut Zygos et tous les autres modules :
- npm
- pnpm
- yarn
- bun
npm install @pithos/core
pnpm install @pithos/core
yarn add @pithos/core
bun add @pithos/core
Étape 2 : Mettre à jour les imports
// Avant
import * as E from "fp-ts/Either";
import * as T from "fp-ts/Task";
import * as TE from "fp-ts/TaskEither";
// Après
import * as E from "pithos/zygos/either";
import * as T from "pithos/zygos/task";
import * as TE from "pithos/zygos/task-either";
Étape 3 : Exécuter vos tests
Toutes les fonctions fonctionnent pareil. pipe, map, flatMap, fold, etc. sont tous compatibles.
Pour la liste complète des méthodes Neverthrow et fp-ts supportées, voir la matrice d'interopérabilité Zygos qui documente chaque fonction à travers Result, ResultAsync, Either, Task et TaskEither.
Zygos fonctionne naturellement avec les fabriques d'erreurs typées de Sphalma : définissez des codes d'erreur structurés avec Sphalma, puis retournez-les comme des valeurs Err typées dans vos chaînes Result.
Ressources associées
- Quand utiliser Zygos — Comparez Zygos avec les alternatives et trouvez quand c'est le bon choix
- Taille de bundle & performance de Zygos — Comparaison détaillée de taille de bundle avec Neverthrow et fp-ts
- Référence API Zygos — Documentation API complète pour Result, Either, Option et plus