Welcome
Introduction
@ts-rust/std is a TypeScript library inspired by Rust’s
Option<T>
and
Result<T, E>
types,
designed to bring type-safe, ergonomic, and robust value and error handling to
JavaScript projects. Built with TypeScript, @ts-rust/std
ensures no runtime
errors are thrown by leveraging static typing and functional programming patterns.
This package is part of the @ts-rust monorepo, which adapts Rust’s standard library concepts into idiomatic TypeScript.
Philosophy
JavaScript often handles optional values and errors using null
, undefined
,
or thrown exceptions—approaches that can lead to runtime errors and untyped,
unpredictable code. In contrast, modern languages like Go and
Rust take a different approach: instead of throwing
exceptions, they return errors as values, forcing the caller to explicitly handle
or ignore them. Inspired by Rust’s Option
and Result
types, @ts-rust/std
brings this disciplined error-handling model to JavaScript and TypeScript,
offering a safer and more explicit way to manage errors and optional values.
In Rust, error handling is deeply integrated into the language. Functions either
return a Result
(or Option
) to indicate success or failure, or they panic to
signal an unrecoverable error. JavaScript, however, operates differently: errors
can be thrown synchronously (caught with try/catch
) or asynchronously (via
rejected promises). While handling both cases is straightforward in theory,
real-world applications often result in "messy" and "noisy" code, especially
when dealing with asynchronous operations like unhandled promise rejections.
@ts-rust/std
addresses this by providing Option
and Result
types—along with
their asynchronous counterparts, PendingOption
and PendingResult
—to simplify
error handling, making it explicit, predictable, and safe.
The core philosophy of this library is to ensure "safe options and results."
Once execution enters a method of Option
, Result
, or their pending variants,
no synchronous or asynchronous exceptions will be thrown or rejected unless
explicitly documented. For example, methods like unwrap
and expect
are
designed to throw (or reject, in async contexts) when called inappropriately,
mirroring Rust’s behavior where a method would panic. In all other cases, errors
are handled gracefully by returning None
or Err
, preventing unexpected runtime
failures. This design makes the library’s behavior predictable and aligns with
Rust’s safety guarantees, adapted for JavaScript’s single-threaded, asynchronous
nature.
JavaScript’s single-threaded model eliminates concerns like race conditions and
unsafe multi-threaded operations (common in Rust’s async runtimes), but it
introduces challenges like properly handling asynchronous behavior—think
"unhandled promise rejection" errors. To address this, @ts-rust/std
clearly
separates synchronous and asynchronous APIs. For instance, many methods on
Result
and Option
restrict their this
type to SettledResult<T, E>
or
SettledOption<T>
, ensuring that the inner value is Awaited<T>
before
operations like unwrap
or check
can be called. The library provides a variety
of methods to help settle promises safely, making async workflows seamless and
type-safe.
Key features of @ts-rust/std
include:
- Type Safety: Leverage TypeScript’s type system to catch errors at compile time.
- No Runtime Surprises: Avoid issues like
undefined is not a function
orunhandled promise rejection
. - Ergonomic Design: Chain operations with methods like
map
,andThen
, andunwrapOr
for a fluent API. - Async Support: Handle asynchronous operations effortlessly with
PendingOption
andPendingResult
.
This library acts as a bridge between Rust’s disciplined approach to safety and
TypeScript’s flexibility, helping you write more predictable, maintainable, and
error-resistant code. Whether you’re handling optional values or managing errors
in synchronous or asynchronous contexts, @ts-rust/std
empowers you to do so
with confidence and clarity.
Installation
Install @ts-rust/std
via package manager of your choice:
npm install @ts-rust/std
yarn add @ts-rust/std
pnpm add @ts-rust/std
Ensure you have TypeScript installed in your project, as this library relies on its type system for maximum benefit.
Usage
Below are some small examples to get you started. For detailed documentation, see:
- Optional Types: Handle optional values with
Option
andPendingOption
. - Result Types: Manage success and failure with
Result
andPendingResult
. - Error Handling: Use custom errors like
AnyError
, extend it to create your own error types, explore built-in errors likeOptionError
,ResultError
, andCheckedError
. - API Reference: Dive into the detailed API documentation generated from the source code.
Handling Optional Values with Option<T>
import { some, none, Option } from "@ts-rust/std";
function findUser(id: number): Option<string> {
return id === 1 ? some("Alice") : none();
}
const user = findUser(1);
console.log(user.unwrapOr("Guest")); // "Alice"
const missingUser = findUser(2);
console.log(missingUser.unwrapOr("Guest")); // "Guest"
Handling Errors with Result<T, E>
import { ok, err, Result } from "@ts-rust/std";
function divide(a: number, b: number): Result<number, string> {
return b !== 0 ? ok(a / b) : err("Division by zero");
}
const success = divide(10, 2);
console.log(success.unwrapOr(0)); // 5
const failure = divide(10, 0);
console.log(failure.unwrapOr(0)); // 0
Async Operations
For asynchronous workflows, use PendingOption
and PendingResult
,
which wrap promises and provide similar methods for chaining operations:
import { pendingResult, ok, err } from "@ts-rust/std";
function fetchData(id: number): PendingResult<string, Error> {
return pendingResult(async () => {
try {
const response = await fetch(
`https://jsonplaceholder.typicode.com/users/${id}`,
);
const data = await response.json();
return ok<{ name: string }, Error>(data as { name: string });
} catch (error) {
return err<{ name: string }, Error>(
error instanceof Error ? error : new Error(`unknown error: ${error}`),
);
}
})
.map((data) => data.name)
.inspectErr((error) => {
console.error(`Failed to fetch data: ${error.get()}`);
});
}
fetchData(1).then((result) => console.log(result.unwrapOr("Unknown")));