Getting Started
Prerequisites
- TypeScript 5.0+
- Node.js 20+
- Any package manager (npm, pnpm, yarn, or bun)
Installation
Install the core package:
- npm
- Yarn
- pnpm
- Bun
npm install antithrow
yarn add antithrow
pnpm add antithrow
bun add antithrow
Optionally install ecosystem packages as needed:
- npm
- Yarn
- pnpm
- Bun
npm install @antithrow/std @antithrow/node @antithrow/standard-schema @antithrow/eslint-plugin
yarn add @antithrow/std @antithrow/node @antithrow/standard-schema @antithrow/eslint-plugin
pnpm add @antithrow/std @antithrow/node @antithrow/standard-schema @antithrow/eslint-plugin
bun add @antithrow/std @antithrow/node @antithrow/standard-schema @antithrow/eslint-plugin
TypeScript configuration
antithrow works with any TypeScript configuration, but strict mode is recommended. These additional options pair well with Result-based error handling:
{
"compilerOptions": {
"strict": true,
"noUncheckedIndexedAccess": true,
"exactOptionalPropertyTypes": true
}
}
Your first Result
Import ok and err to create Result values, and the Result type for annotations:
import { ok, err, type Result } from "antithrow";
function divide(a: number, b: number): Result<number, string> {
if (b === 0) return err("division by zero");
return ok(a / b);
}
Check the variant with isOk() / isErr() — these are type predicates that narrow the type:
const result = divide(10, 3);
if (result.isOk()) {
console.log(result.value); // number
} else {
console.error(result.error); // string
}
Or use match() for exhaustive handling in one expression:
const message = divide(10, 3).match({
ok: (value) => `Result: ${value}`,
err: (error) => `Error: ${error}`,
});
Wrapping existing code
Use Result.try() to wrap functions that throw:
import { Result } from "antithrow";
const parsed = Result.try(() => JSON.parse('{"name": "Alice"}'));
// Result<any, unknown>
For standard globals like JSON.parse, fetch, atob, and others, @antithrow/std provides pre-built wrappers with precise error types:
import { JSON } from "@antithrow/std";
const parsed = JSON.parse<{ name: string }>('{"name": "Alice"}');
// Result<{ name: string }, SyntaxError>
For Node.js APIs like fs/promises, @antithrow/node provides wrappers with precise error types:
import { readFile, writeFile } from "@antithrow/node/fs/promises";
const content = await readFile("config.json", "utf-8");
// ResultAsync<string, NodeJS.ErrnoException>
Setting up the ESLint plugin
@antithrow/eslint-plugin provides type-aware rules to catch common mistakes. Add the recommended config to your ESLint flat config:
// eslint.config.ts
import antithrow from "@antithrow/eslint-plugin";
export default [
antithrow.configs.recommended,
// ... your other configs
];
This enables three rules:
| Rule | Severity | Description |
|---|---|---|
@antithrow/no-unused-result | error | Require Result values to be used |
@antithrow/no-unsafe-unwrap | warn | Disallow unwrap() / expect() on unhandled Results |
@antithrow/no-throwing-call | warn | Flag throwing APIs that have @antithrow/std replacements |
The ESLint plugin requires type-aware linting via typescript-eslint. See the full setup guide for details.
Next steps
- Result<T, E> — Deep dive into the core type
- ResultAsync<T, E> — Async error handling
- Composing with chain() — Generator-based composition
- API Reference — Complete API documentation