Skip to content

unthrownExplicit errors as values

A small, focused Result type with a separate defect channel for the unexpected — and qualification enforced at every boundary.

unthrown

At a glance ​

ts
import { ok, err, fromPromise, type Result } from "unthrown";

class NotFound extends TaggedError("NotFound") {}

function findUser(id: string): Result<User, NotFound> {
  const user = users.get(id);
  return user ? ok(user) : err(new NotFound());
}

// Cross an async boundary — every rejection MUST be triaged.
const profile = fromPromise(fetch(`/u/${id}`), (cause) =>
  cause instanceof Response ? new NotFound() : defect(cause),
);

// Handle every channel once, at the edge — no surrounding try/catch.
const status = await profile.match({
  ok: () => 200,
  err: () => 404,
  defect: () => 500,
});

Ordinary errors travel as values through map / flatMap / match. A thrown bug becomes a defect that short-circuits to the edge — never silently folded into your domain errors.

Released under the MIT License.