UNPKG

@ts-rust/std

Version:

Rust-inspired utilities for TypeScript: Option, Result, and error handling for safer, more predictable code.

173 lines (134 loc) 7.26 kB
# @ts-rust/std A TypeScript library inspired by Rust’s [`Option<T>`](https://doc.rust-lang.org/std/option/enum.Option.html) and [`Result<T, E>`](https://doc.rust-lang.org/std/result/enum.Result.html) 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](https://go.dev/) and [Rust](https://www.rust-lang.org/) 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` or `unhandled promise rejection`. - **Ergonomic Design**: Chain operations with methods like `map`, `andThen`, and `unwrapOr` for a fluent API. - **Async Support**: Handle asynchronous operations effortlessly with `PendingOption` and `PendingResult`. 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 npm, yarn, or pnpm: ```bash 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 Here are some quick examples to get you started. For detailed documentation, see: - [TypeDoc documentation](https://krawitzzz.github.io/ts-rust/) - [Option README](./src/option/README.md) - [Result README](./src/result/README.md) ### Handling Optional Values with `Option<T>` ```typescript 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>` ```typescript 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: ```typescript 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"))); ``` ## Key Exports - `Option<T>`, `some`, `none`: For handling optional values. - `Result<T, E>`, `ok`, `err`: For handling success/error scenarios. - `PendingOption<T>`, `pendingOption`, `pendingSome`, `pendingNone`: Async optional values. - `PendingResult<T, E>`, `pendingResult`, `pendingOk`, `pendingErr`: Async success/error handling. ## Contributing We welcome contributions! If you find a bug or have a feature request: 1. Check the [issue tracker](https://github.com/krawitzzZ/ts-rust/issues) to see if it’s already reported. 2. Open a new issue with a clear title, description, and reproduction steps (if applicable). 3. For code contributions, fork the repo, create a branch, and submit a pull request. Please follow the [code of conduct](../../CODE_OF_CONDUCT.md) when interacting with the project.