@fuzzy-street/results v0.3.3
Result Pattern
A highly optimized, fully type-safe, dependency-free utility for representing operations that can either succeed or fail.
Complete with:
- Comprehensive functional transformations
- Advanced error handling capabilities
- Async/Promise integration
- Performance optimizations
- Elegant composition patterns
Its a fuzzy approach where by having better results we can craft more reliable code that doesn't rely on try/catch and exceptions for control flow.
π Overview
This library aims to provide an elegant solution for handling operations that can succeed or fail in TypeScript applications. It addresses the common problems with traditional exception-based error handling while maintaining full type safety and composability.
Unlike traditional error handling with exceptions, this library seeks to enable us with the following:
- Explicit error handling with proper type information
- Composable operations that might fail
- Functional transformations of success and error values
- Predictable control flow without hidden exceptional paths
- Better testability through deterministic error handling
- Performance optimizations for high-throughput scenarios
β¨ Features
π§ββοΈ Type-Safe Results - Experience bulletproof type safety with full TypeScript inference and precise error typing. No more "any" type nightmares or runtime surprises.
π Powerful Functional Transformations - Transform your data with elegant, chainable operations like
map,chain, andpipe. Build complex processing flows with minimal code.πͺ Painless Composition - Compose operations that might fail without deeply nested try/catch blocks. Create clean, readable code that's easy to maintain and extend.
𧬠First-Class Async Support - Handle async operations with the same elegant API. Convert Promises to Results, chain async operations, and process multiple async results in parallel.
β οΈ Explicit Error Handling - Say goodbye to forgotten try/catch blocks and silent failures. Every potential error becomes a value you can inspect, transform, and handle with precision.
π Control Your Own Destiny - Decide exactly when and how to extract values from results with smart unwrapping operations that prevent runtime crashes.
π Railway-Oriented Programming - Implement the powerful railway pattern with built-in short-circuiting. Keep your happy path clean while ensuring errors naturally flow to error handlers.
β‘ Blazing Fast Performance - Meticulously optimized for speed and minimal memory usage. We've benchmarked extensively to ensure near-zero overhead compared to traditional error handling.
π₯ Advanced Concurrency - Process tasks with controlled parallelism, built-in retry logic, and intelligent error handling for complex async workflows. -->
π€ Rich Combinators - Combine multiple results with sophisticated utilities like
asyncAlland sophisticated error aggregation. No more manual result merging.π» Developer Experience First - Designed for humans with clear naming, consistent behavior, and detailed documentation with practical examples for every function.
π Zero Dependencies - Not a single external dependency. Just pure, optimized TypeScript that won't bloat your bundle or introduce security vulnerabilities.
π Universal Compatibility - Works anywhere JavaScript runs: browsers, Node.js, Deno, Bun, web workers, or serverless functions. One API to rule them all.
πͺ Battle-Tested - Comprehensive guides with real-world examples for every function. Learn through practical code, not just abstract theory.
π Installation
# Using npm
npm install @fuzzy-street/results
# Using yarn
yarn add @fuzzy-street/results
# Using pnpm
pnpm add @fuzzy-street/resultsπ Core Concepts
Result Pattern is built around a simple concept: a function that can either succeed or fail returns a Result<T, E> type, which is either:
{ status: "success", data: T }for successful operations{ status: "error", error: E }for failed operations
This allows you to: 1. Make error handling explicit and type-safe 2. Create pipelines of operations where errors naturally short-circuit 3. Eliminate try/catch blocks for control flow 4. Ensure all error cases are handled
π§© Basic Usage
import { success, error, isSuccess, isError, match } from '@fuzzy-street/results';
// Creating success results
const successResult = success(42);
// { status: "success", data: 42 }
// Creating error results
const errorResult = error(new Error('Something went wrong'));
// { status: "error", error: Error("Something went wrong") }
// Type checking
if (isSuccess(successResult)) {
console.log(successResult.data); // 42
}
if (isError(errorResult)) {
console.log(errorResult.error.message); // "Something went wrong"
}
// Pattern matching
const message = match(successResult, {
success: (value) => `Success: ${value}`,
error: (err) => `Error: ${err.message}`
});
// "Success: 42"π Library Structure
The library is organized into three main categories:
Core Functions
These form the foundation of the Result pattern:
success: Creates a successful resulterror: Creates an error resultisSuccess: Type guard for successful resultsisError: Type guard for error resultsisResult: Type guard for any resultmatch: Pattern matching for resultsunwrap: Extracts value or throws errorunwrapOr: Extracts value with fallback
Transformer Functions
These help transform and process results:
map: Transforms success valuesmapError: Transforms error valueschain: Chains operations that might failtap: Performs side effects on any resulttapSuccess: Performs side effects on success resultstapError: Performs side effects on error resultspipe: Creates transformation pipelinescreateErrorBoundary: Creates error-handling boundaries
Async Functions
These handle asynchronous operations:
fromPromise: Converts a Promise to a ResultfromAsync: Wraps an async function to return a ResultasyncMap: Maps a Result value asynchronouslyasyncMapError: Maps a Result error asynchronouslyasyncChain: Chains async operations that return ResultsasyncPipe: Creates async transformation pipelinesasyncAll: Combines multiple async ResultswithFinally: Executes cleanup after async operationscreateAsyncErrorBoundary: Creates async error-handling boundaries
Each function has detailed documentation and examples in the linked markdown files. We highly recommend exploring these docs to understand the full capabilities of each utility.
π Advanced Examples
Railway-Oriented Programming
import { pipe, success, error } from '@fuzzy-street/results';
function validateInput(input: string) {
return input ? success(input) : error(new Error('Input required'));
}
function processInput(input: string) {
return input.length >= 3
? success(input.toUpperCase())
: error(new Error('Input too short'));
}
function formatOutput(input: string) {
return success(`Processed: ${input}`);
}
// Create a processing pipeline
const result = pipe(
'hello', // Input value
validateInput, // Validate (short-circuit if invalid)
processInput, // Process (short-circuit if fails)
formatOutput // Format output
);
// result: { status: "success", data: "Processed: HELLO" }Async Operations
import { asyncChain, fromPromise } from '@fuzzy-street/results';
async function fetchUser(id: string) {
return fromPromise(
fetch(`https://api.example.com/users/${id}`)
.then(response => {
if (!response.ok) throw new Error(`HTTP error ${response.status}`);
return response.json();
})
);
}
async function fetchUserPosts(user) {
return fromPromise(
fetch(`https://api.example.com/users/${user.id}/posts`)
.then(response => {
if (!response.ok) throw new Error(`HTTP error ${response.status}`);
return response.json();
})
);
}
// Chain async operations
async function getUserWithPosts(userId: string) {
const userResult = await fetchUser(userId);
return await asyncChain(userResult, fetchUserPosts);
}Error Handling
import { match, success, error } from '@fuzzy-street/results';
function divideNumbers(a: number, b: number) {
return b !== 0
? success(a / b)
: error(new Error('Division by zero'));
}
const result = divideNumbers(10, 0);
// Pattern matching for elegant error handling
const message = match(result, {
success: (value) => `Result: ${value}`,
error: (err) => `Error: ${err.message}`
});
// message: "Error: Division by zero"β‘Performance
The Result pattern has been carefully optimized to minimize overhead:
- Minimal object creation in transformations
- Early short-circuiting to avoid unnecessary processing
- Efficient memory usage with optimized data structures
- Benchmarks show minimal overhead compared to direct function calls
According to our benchmarks:
- Function call overhead is acceptable for most real-world use cases
- Error handling with Results is actually faster than traditional try/catch in many scenarios
- Memory overhead is minimal
π§ββοΈ TypeScript Support
This library is built with TypeScript first in mind:
- Full type inference for all operations
- Generic type parameters for flexible usage
- Type guards for runtime type checking
- Type narrowing for improved developer experience
π§ͺ Running Examples
This repository comes with a comprehensive set of examples to demonstrate the usage of each function. To run them locally:
Clone the repository:
git clone https://github.com/fuzzy-st/results.git cd resultsInstall dependencies:
pnpm installRun a specific example:
pnpm tsx src/examples/core/success.ts pnpm tsx src/examples/transformers/pipe.ts pnpm tsx src/examples/async/asyncChain.ts
Each example file contains multiple usage patterns. To try a specific example, uncomment the corresponding run...() function at the bottom of the file before running it.
For example, in src/examples/core/success.ts:
// Uncomment any of these to run the example
// runBasicExample();
// runValidationExample();
runComplexExample(); // This one will executeWe encourage you to explore these examples to get a feel for how the library works in practice. Each example corresponds to the documentation for its respective function.
π€ Contributing
Contributions are welcome! Please feel free to submit a Pull Request.
π License
This project is licensed under the MIT License - see the LICENSE file for details.