A TypeScript library implementing Rust-like error handling with Result
, Ok
, and Err
types, promoting type-safe and explicit error management.
JavaScript/TypeScript error handling often relies on try...catch
blocks or nullable return types, which can be verbose or hide potential errors. rustify
brings the Result
type, a pattern widely used in Rust, to TypeScript. This allows you to:
- Handle errors explicitly: Functions return a
Result
which is eitherOk(value)
for success orErr(error)
for failure. - Improve type safety: The types
T
(success) andE
(error) are tracked by the type system. - Chain operations safely: Methods like
andThen
andorElse
allow elegant chaining. - Perform exhaustive checks: The
match
method ensures you handle bothOk
andErr
cases explicitly. - Easily wrap unsafe functions:
Result.from
provides a simple way to convert functions that might throw errors into functions that return aResult
. - Destructure results easily: Use
asTuple()
for Go-style[err, val]
destructuring, orasObject()
if you prefer{ error, value }
destructuring.
You can install rustify
using your favorite package manager or directly from jsr.
npm:
npm install @ghaerdi/rustify
# or
yarn add @ghaerdi/rustify
# or
pnpm add @ghaerdi/rustify
jsr:
npx jsr add @ghaerdi/rustify
# or
bunx jsr add @ghaerdi/rustify
# or
deno add @ghaerdi/rustify
Import Ok
, Err
, and Result
from the library.
import { Result, Ok, Err } from "@ghaerdi/rustify";
// --- Creating a function that returns a Result ---
// Example: A function that performs division but returns Err for division by zero
function divide(numerator: number, denominator: number): Result<number, string> {
if (denominator === 0) {
return Err("Cannot divide by zero"); // Failure case
}
const result = numerator / denominator;
return Ok(result); // Success case
}
// --- Using the function and handling the Result ---
const result = divide(10, 2); // Try change 2 to 0 for an Err case
// Use 'match' to exhaustively handle both Ok and Err cases.
// This is often the clearest way to ensure all possibilities are handled.
const message = result.match({
Ok: (value) => {
// This runs only if result is Ok
console.log(`Match Ok: Division successful, value is ${value}`);
return `Result: ${value}`;
},
Err: (errorMessage) => {
// This runs only if result is Err
console.error("Match Err:", errorMessage);
return `Error: ${errorMessage}`;
}
});
console.log(message);
// Other methods like Result.from, isOk, map, andThen, unwrapOrElse, asTuple etc.
// allow for wrapping functions, specific checks, transformations, and handling patterns.
// See the API Overview section for more details.
Result<T, E>
: The main type, representing either success (Ok<T>
) or failure (Err<E>
).Ok<T>
: Represents a successful result containing a value of typeT
. Created using theOk(value)
function.- If
T
is iterable (like an Array or String), theOk
instance itself becomes iterable.
- If
Err<E>
: Represents a failure containing an error value of typeE
. Created using theErr(error)
function.
The Result
type provides numerous methods for handling and transformation:
- Checking:
isOk()
: Returnstrue
ifOk
.isErr()
: Returnstrue
ifErr
.isOkAnd(fn)
: Returnstrue
ifOk
and the value satisfiesfn
.isErrAnd(fn)
: Returnstrue
ifErr
and the error satisfiesfn
.
- Extracting Values:
ok()
: Returns theOk
value orundefined
.err()
: Returns theErr
value orundefined
.unwrap()
: Returns theOk
value, throws ifErr
. Use with caution.unwrapErr()
: Returns theErr
value, throws ifOk
.expect(message)
: ReturnsOk
value, throwsmessage
ifErr
.expectErr(message)
: ReturnsErr
value, throwsmessage
ifOk
.unwrapOr(defaultValue)
: ReturnsOk
value ordefaultValue
ifErr
.unwrapOrElse(fn)
: ReturnsOk
value or computes default usingfn(errorValue)
ifErr
.
- Mapping & Transformation:
map(fn)
: MapsOk<T>
toOk<U>
. LeavesErr
untouched.mapErr(fn)
: MapsErr<E>
toErr<F>
. LeavesOk
untouched.mapOr(defaultValue, fn)
: Appliesfn
toOk
value, returnsdefaultValue
ifErr
.mapOrElse(defaultFn, fn)
: Appliesfn
toOk
value, appliesdefaultFn
toErr
value.
- Chaining & Side Effects:
and(res)
: Returnsres
ifOk
, else returns self (Err
).andThen(fn)
: Callsfn(okValue)
ifOk
, returns the resultingResult
.or(res)
: Returnsres
ifErr
, else returns self (Ok
).orElse(fn)
: Callsfn(errValue)
ifErr
, returns the resultingResult
.inspect(fn)
: Callsfn(okValue)
ifOk
, returns originalResult
.inspectErr(fn)
: Callsfn(errValue)
ifErr
, returns originalResult
.
- Pattern Matching:
match(matcher)
: Executesmatcher.Ok(value)
ormatcher.Err(error)
, returning the result.
- Cloning:
cloned()
: Returns a newResult
with a deep clone of theOk
value (usingstructuredClone
).Err
values are not cloned.
- Destructuring / Representation:
asTuple()
: Represents the Result's state as a tuple[error, value]
. Returns[undefined, T]
forOk(T)
and[E, undefined]
forErr(E)
.asObject()
: Represents the Result's state as an object{ error, value }
. Returns{ error: undefined, value: T }
forOk(T)
and{ error: E, value: undefined }
forErr(E)
.
- Utilities (Static Methods on
Result
):Result.from(fn, errorTransform?)
: Wraps a sync functionfn
that might throw. Executesfn
. ReturnsOk(result)
orErr(error)
.Result.fromAsync(fn, errorTransform?)
: Wraps an async functionfn
returning a Promise. ReturnsPromise<Result>
. Handles resolution/rejection.Result.isResult(value)
: Type guard, returnstrue
ifvalue
isOk
orErr
.wrapInResult(fn, errorTransform?)
: [Deprecated] UseResult.from(() => fn(...args))
instead.
This project uses Bun.
- Install Dependencies:
bun install
- Type Checking:
bun run check --watch
- Run Tests:
bun test --watch
Contributions welcome! Please submit issues and pull requests.
- Fork the repository.
- Create your feature branch.
- Commit your changes.
- Push to the branch.
- Open a Pull Request.
MIT License - see the LICENSE file for details.