simple-monad
    Preparing search index...

    02 — Form validation (matchBad)

    Several distinct failure modes: each rule fails with its own Bad<tag, payload> leaf, so the return type is a union of leaves. Result.matchBad dispatches on the tag, and each handler sees the payload typed for that tag — adding a rule is just one more union member and one more handler.

    Run it: node examples/02-form-validation.ts

    /**
    * Example 02 — several distinct failure modes (`matchBad`).
    *
    * Each rule fails with its own `Bad<tag, payload>` leaf, so the return type is a
    * union of leaves. `Result.matchBad` dispatches on the tag, and each handler sees
    * the payload typed for *that* tag — adding a rule is just one more union member
    * and one more handler.
    */
    import { bad, type Bad, ok, type Ok, Result } from "simple-monad";

    interface Signup {
    email: string;
    password: string;
    age: number;
    }

    type SignupError =
    | Bad<"missing_email", void>
    | Bad<"weak_password", { minLength: number }>
    | Bad<"underage", { age: number; required: number }>;

    function validateSignup(input: Signup): Ok<Signup> | SignupError {
    if (!input.email.includes("@")) return bad("missing_email"); // tag-only failure
    if (input.password.length < 8) return bad("weak_password", { minLength: 8 });
    if (input.age < 18) return bad("underage", { age: input.age, required: 18 });
    return ok(input);
    }

    function describe(input: Signup): string {
    const result = validateSignup(input);
    // matchBad requires a Bad, so handle the success first — the early return also
    // narrows `result` to the SignupError union for the call below.
    if (result.isOk()) return "✓ signup accepted";
    return Result.matchBad(result, {
    missing_email: () => "email must contain @",
    weak_password: (b) => `password needs ${b.value.minLength}+ chars`,
    underage: (b) => `must be ${b.value.required}, got ${b.value.age}`,
    });
    }

    const okInput = { email: "a@b.co", password: "longenough", age: 30 };
    console.log(`Input: ${JSON.stringify(okInput)}`);
    console.log(describe(okInput));

    const badInput = { email: "nope", password: "x", age: 12 };
    console.log(`Input: ${JSON.stringify(badInput)}`);
    console.error(describe(badInput)); // a rejected signup — report on stderr