Aller au contenu principal

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/core/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​

MonadeDescriptionCas d'usage
ResultOk<T> ou Err<E>Opérations qui peuvent échouer
OptionSome<A> ou NoneValeurs optionnelles (pas de null)
EitherLeft<E> ou Right<A>Branchement générique à deux cas
TaskCalcul async paresseuxOpérations async différées
TaskEitherEither asyncOpé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/core/zygos/result/result";
import { ResultAsync } from "@pithos/core/zygos/result/result-async";

// Votre code existant fonctionne sans changement
Migration

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/core/zygos/result/result";
import { ResultAsync } from "@pithos/core/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/core/zygos/option";
import { pipe } from "@pithos/core/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/core/zygos/either";
import * as T from "@pithos/core/zygos/task";
import * as TE from "@pithos/core/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))
);
Migration

Rechercher & remplacer from "fp-ts/Either" → from "@pithos/core/zygos/either", etc. Toutes les fonctions fonctionnent pareil.

Fonctions disponibles​

ModuleFonctions
Eitherleft, right, isLeft, isRight, map, mapLeft, flatMap, fold, match, getOrElse, orElse, fromOption, fromNullable, tryCatch, Do, bind, bindTo, apS
Taskof, map, flatMap, ap
TaskEitherleft, 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/core/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 → ResultAsync pour une gestion d'erreurs typée
  • Chaînes de validation → Result avec andThen
  • Données optionnelles → Option au lieu de null | undefined
  • Encapsuler du code unsafe → safe() pour éliminer les try/catch
Kanon + Zygos

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 :

BesoinUtilisez plutôt
Validation de schémasKanon
Transformation de donnéesArkhe
Fabriques d'erreurs typéesSphalma

Migrer depuis Neverthrow ou fp-ts​

Depuis Neverthrow​

Étape 1 : Installer​

Ajoutez Pithos à votre projet. Il inclut Zygos et tous les autres modules :

npm install @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/core/zygos/result/result";
import { ResultAsync } from "@pithos/core/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/core/zygos/result/result";

// Try async simplifié
import { safeAsyncTry } from "@pithos/core/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 install @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/core/zygos/either";
import * as T from "@pithos/core/zygos/task";
import * as TE from "@pithos/core/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