antithrow
v2.0.0
Published
Rust-style Result types for type-safe error handling without exceptions
Downloads
22
Maintainers
Readme
Features
- Explicit failures - return types show exactly which functions can fail and how.
- Compiler-enforced - TypeScript ensures you handle both
OkandErr. - Type-safe errors - error types are known at compile time.
- Sync + async support - compose workflows with both
Result<T, E>andResultAsync<T, E>. - Ergonomic chaining - use
chain(...)+yield*for readable happy-path flow with early exits on failure. - Familiar API - based heavily on Rust's battle-tested
std::result.
Installation
bun add antithrowUsage
Check out our examples for a list of working demos!
import type { Result } from "antithrow";
import { err, ok } from "antithrow";
type ConfigError =
| { type: "missing_env"; key: string }
| { type: "invalid_port"; value: string };
const readEnv = (key: string): Result<string, ConfigError> => {
const value = process.env[key];
return value ? ok(value) : err({ type: "missing_env", key });
};
const parsePort = (value: string): Result<number, ConfigError> => {
const port = Number(value);
return Number.isInteger(port) && port > 0 && port <= 65535
? ok(port)
: err({ type: "invalid_port", value });
};
const port = readEnv("PORT").andThen(parsePort).unwrapOr(3000);[!WARNING]
antithrowpreserves theResult<T, E>error kind. Because of that, it does not implicitly convert thrown values from callbacks or generator bodies intoErr<E>.
- Callbacks passed to methods like
map,mapErr,andThen,orElse,inspect(and async variants) can still throw/reject.chain(...)generator bodies can still throw/reject.If logic can throw, wrap it explicitly with
Result.try(...)orResultAsync.try(...)before feeding it into pipelines. Or use@antithrow/stdwhich provides pre-wrapped versions of common globals.const safeJsonParse = (input: string): Result<unknown, SyntaxError> => Result.try(() => JSON.parse(input)); const result = ok('{"a":1}').andThen(safeJsonParse);
Getting Started
Transformations
import { ok } from "antithrow";
const result = ok(2)
.map((x) => x * 2) // ok(4)
.andThen((x) => ok(x + 1)) // ok(5)
.unwrapOr(0); // 5Async Results
import { chain, okAsync, ResultAsync } from "antithrow";
// Wrap async throwing functions
const fetched = ResultAsync.try(async () => {
const response = await fetch("/api/data");
return response.json();
});
// Chain async operations
const result = await chain(async function* () {
const a = yield* okAsync(1);
const b = yield* okAsync(2);
return a + b;
});
// ok(3)Chain Multiple Results
interface RequestError {
status: number;
message: string;
}
async function handler(request: Request): Promise<Response> {
const result = await chain(async function* () {
const { email, name } = yield* parseBody(request);
const validEmail = yield* validateEmail(email);
yield* checkEmailAvailable(validEmail);
return yield* saveUser(validEmail, name);
});
return result.match({
ok: (user) => Response.json(user, { status: 201 }),
err: ({ status, message }) => Response.json({ error: message }, { status }),
});
}API
Constructors
| Function | Description |
| ---------------------------------- | ------------------------------------------------- |
| ok(value?) | Creates a successful result |
| err(error) | Creates a failed result |
| okAsync(value?) | Creates an async successful result |
| errAsync(error) | Creates an async failed result |
| Result.try(fn) | Wraps a throwing function in a Result |
| Result.all(results) | Combines multiple Results into one |
| ResultAsync.try(fn) | Wraps an async throwing function in a ResultAsync |
| ResultAsync.all(results) | Combines multiple Results/ResultAsyncs into one |
| ResultAsync.fromPromise(promise) | Wraps a Promise<Result> in a ResultAsync |
| chain(generator) | Chains results using generator syntax |
Methods
Both Result and ResultAsync support:
| Method | Description |
| -------------------------- | ---------------------------------------------------------------- |
| isOk() | Type predicate for success |
| isErr() | Type predicate for failure |
| isOkAnd(fn) | Returns true if Ok and predicate passes |
| isErrAnd(fn) | Returns true if Err and predicate passes |
| unwrap() | Returns value or throws |
| unwrapErr() | Returns error or throws |
| expect(message) | Returns value or throws with message |
| expectErr(message) | Returns error or throws with message |
| unwrapOr(default) | Returns value or default |
| unwrapOrElse(fn) | Returns value or computes from error |
| map(fn) | Transforms the success value |
| mapErr(fn) | Transforms the error value |
| mapOr(default, fn) | Transforms or returns default |
| mapOrElse(defaultFn, fn) | Transforms or computes default |
| andThen(fn) | Chains with another Result-returning function |
| and(result) | Returns the provided result if Ok |
| or(result) | Returns this result if Ok, otherwise the provided result |
| orElse(fn) | Recovers from error with another Result |
| match({ ok, err }) | Pattern matches on the result |
| inspect(fn) | Side effects on success value |
| inspectErr(fn) | Side effects on error value |
| flatten() | Flattens nested Result<Result<U, F>, E> to Result<U, E \| F> |
