try-results
v0.0.6
Published
A minimal, functional, and tree-shakable Result library for TypeScript that prioritizes simplicity and serialization
Readme
try-results is a minimal, functional, and tree-shakable Result library for TypeScript that prioritizes simplicity and serialization.
- 🔮 Simple, declarative API: Intuitive array destructuring with full type safety
- 🍃 Lightweight & Tree Shakable: Function-based design with zero dependencies
- ⚡ High Performance: Minimal overhead with just a 3-element array
- 🔍 Easy Serialization: Simple array format perfect for wire transmission
- 📦 Zero Dependencies: Standalone library ensuring ease of use in various environments
- 🔧 Functional Helpers: Powerful map, unwrap, and utility functions
- 🧵 Type Safe: Full TypeScript support with literal types and type guards
🌟 Motivation
Build a minimal, functional Result library that prioritizes simplicity and serialization. While libraries like ts-results and neverthrow offer robust features, they often come with bloated class hierarchies that can't be easily serialized. try-results provides a simpler alternative - combining minimal overhead, easy serialization for APIs and frameworks like React Router, and functional helpers while adhering to the KISS principle.
Key Features:
- Minimal Core: Just a 3-element array
[boolean, E, T]with methods - Easy Serialization: Perfect for APIs, Remix loaders, and network requests
- Array Destructuring: Intuitive
[ok, error, value]pattern - Tree Shakable: Import only what you need
⚖️ Alternatives
📖 Usage
try-results provides a simple approach to error handling. Here's how to use it:
1. Creating Results
import { Ok, Err } from 'try-results';
const success = Ok(42);
const failure = Err('Something went wrong');2. Working with Results
// Method-based approach
if (success.isOk()) {
console.log(success.value); // 42
}
// Array destructuring approach
const [ok, error, value] = success;
if (ok) {
console.log(value); // 42
}
// Direct unwrapping (throws on error)
const value = success.unwrap(); // 423. Safe Value Extraction
import { unwrapOr, unwrapErr } from 'try-results';
// Provide defaults
const value = unwrapOr(failure, 0); // 0
// Extract errors safely
const error = unwrapErr(failure); // 'Something went wrong'4. Transforming Results
import { mapOk, mapErr } from 'try-results';
// Transform success values
const doubled = mapOk(success, x => x * 2); // Ok(84)
// Transform errors
const wrapped = mapErr(failure, e => `Error: ${e}`); // Err('Error: Something went wrong')5. Wrapping Functions
import { t, tAsync } from 'try-results';
// Wrap synchronous functions
const result = t(() => JSON.parse('invalid')); // Err(SyntaxError)
// Wrap promises
const asyncResult = await tAsync(fetch('/api/data')); // Ok(Response) or Err(Error)6. Serialization
import { serialize, deserialize } from 'try-results';
// Convert to wire format
const wireFormat = serialize(success); // [true, 42]
// Reconstruct from wire format
const reconstructed = deserialize(wireFormat); // Back to TResult📚 API Reference
Core Functions
Ok<T, E>(value: T): OkResult<T, E>
Creates a successful result containing the given value.
const result = Ok(42);
console.log(result.unwrap()); // 42
console.log(result.isOk()); // trueErr<T, E>(error: E): ErrResult<T, E>
Creates an error result containing the given error.
const result = Err('Something went wrong');
console.log(result.isErr()); // true
console.log(result.error); // 'Something went wrong'Type Guards
isOk<T, E>(result: TResult<T, E>): result is OkResult<T, E>
Type guard to check if a result is successful.
if (isOk(result)) {
// TypeScript knows result is OkResult here
console.log(result.unwrap());
}isErr<T, E>(result: TResult<T, E>): result is ErrResult<T, E>
Type guard to check if a result is an error.
if (isErr(result)) {
// TypeScript knows result is ErrResult here
console.log(result.error);
}Unwrapping Functions
unwrap<T, E>(result: TResult<T, E>): T
Extracts the value from a result, throwing if it's an error.
try {
const value = unwrap(success); // 42
} catch (error) {
// Handle error
}unwrapOk<T, E>(result: TResult<T, E>): T
Extracts the value from an Ok result, throwing if it's an error.
const value = unwrapOk(success); // 42unwrapErr<T, E>(result: TResult<T, E>): E
Extracts the error from an Err result, throwing if it's successful.
const error = unwrapErr(failure); // 'Something went wrong'unwrapOr<T, E>(result: TResult<T, E>, defaultValue: T): T
Extracts the value from a result, returning a default if it's an error.
const value = unwrapOr(failure, 0); // 0unwrapOrNull<T, E>(result: TResult<T, E>): T | null
Extracts the value from a result, returning null if it's an error.
const value = unwrapOrNull(failure); // nullTransformation Functions
mapOk<T, E, U>(result: TResult<T, E>, mapFn: (value: T) => U): TResult<U, E>
Maps the value inside an Ok result using the provided function.
const doubled = mapOk(Ok(21), x => x * 2); // Ok(42)mapErr<T, E, F>(result: TResult<T, E>, mapFn: (error: E) => F): TResult<T, F>
Maps the error inside an Err result using the provided function.
const wrapped = mapErr(Err(404), code => `HTTP ${code}`); // Err('HTTP 404')Function Wrappers
t<T, Args extends any[]>(fn: (...args: Args) => T, ...args: Args): TResult<T, unknown>
Wraps a synchronous function call in a Result.
const result = t(() => JSON.parse('invalid')); // Err(SyntaxError)
const safeDivide = (a: number, b: number) => t(() => a / b, a, b);tAsync<T>(promise: Promise<T>): Promise<TResult<T, unknown>>
Wraps a Promise in a Result.
const result = await tAsync(fetch('/api/data')); // Ok(Response) or Err(Error)Serialization Functions
serialize<T, E>(result: TResult<T, E>): [boolean, T | E]
Converts a result to a wire-friendly format.
const wireFormat = serialize(Ok(42)); // [true, 42]deserialize<T, E>(serialized: [boolean, T | E]): TResult<T, E>
Converts a serialized result back to a TResult.
const result = deserialize([true, 42]); // Ok(42)💡 Resources / References
- try operator proposal - ECMAScript proposal that inspired our array destructuring
- ts-results
- neverthrow
