npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@moon7/result

v0.1.1

Published

TypeScript Result type for functional error handling

Readme

@moon7/result

npm version License: MIT

A lightweight, zero-dependency TypeScript library for handling operations that might fail in a functional way.

Features

  • 🛡️ Type-safe error handling - Handle success and failure states without exceptions
  • 🧩 Composable operations - Chain operations that might fail with clean, readable code
  • 🔄 Async support - Full support for asynchronous operations with promises
  • 🧪 Pattern matching - Elegant pattern matching for handling different result states
  • 📦 Zero dependencies - Lightweight and focused utility

Installation

# npm
npm install @moon7/result

# yarn
yarn add @moon7/result

# pnpm
pnpm add @moon7/result

Core Concepts

Result Type

The core of the library is the Result<V, E> type, which can be either a Success<V> or a Failure<E>:

type Result<V, E = unknown> = Success<V> | Failure<E>;

interface Success<V> {
    readonly value: V;
}

interface Failure<E> {
    readonly error: E;
}

Maybe Type

The library includes a Maybe<T> type for handling optional values in a functional way. It's unified with the Result type, meaning all Result operations work seamlessly with Maybe:

import { some, none, isSome, isNone, Maybe } from '@moon7/result';
import { map, chain, unwrapOr } from '@moon7/result';

// Creating Maybe values
const someValue = some(42);        // Contains a value
const noneValue = none;            // Represents absence of a value

// Type guards
if (isSome(someValue)) {
    console.log(someValue.value);  // 42
}

// Safely extracting values
const value = unwrapOr(someValue, 0);  // 42
const fallback = unwrapOr(noneValue, 0); // 0

// Transformations
const doubled = map(someValue, x => x * 2);  // some(84)
const chained = chain(someValue, x => x > 20 ? some(x) : none);  // some(42)

The Maybe type is implemented as a specialized Result where Some<T> is a Success<T> and None is a Failure<null>. This allows you to reuse all the Result utility functions with Maybe values.

Outcome Type

The Outcome<V, E> type represents the common Node.js callback argument pattern of (error, value) tuples:

import { Outcome, fromOutcome } from '@moon7/result';

// Outcome is a [error, value] tuple, common in Node.js callbacks
type SuccessOutcome<V> = [undefined | null, V];
type FailureOutcome<E> = [E, undefined];
type Outcome<V, E = unknown> = SuccessOutcome<V> | FailureOutcome<E>;

// Converting from Outcome to Result
const nodeOutcome: Outcome<string, Error> = [null, "operation succeeded"];
// Success with "operation succeeded"
const result = fromOutcome(nodeOutcome);

const errorOutcome: Outcome<string, Error> = [new Error("operation failed"), undefined];
// Failure with Error("operation failed")
const errorResult = fromOutcome(errorOutcome);

The Outcome type is primarily used:

  • As a representation of Node.js callback argument tuples
  • For conversion to Result via fromOutcome() to leverage Result's rich API

Basic Usage

import { success, failure, isSuccess, unwrapOr } from '@moon7/result';

// Creating Results
const successResult = success(42);
const failureResult = failure(new Error("Something went wrong"));

// Checking result type
if (isSuccess(successResult)) {
    console.log(successResult.value); // 42
}

// Safely extracting values with fallbacks
const value = unwrapOr(failureResult, 0); // 0

Safe Operations

import { fromTry, fromPromise } from '@moon7/result';

// Safe synchronous operations
const result = fromTry(() => JSON.parse(someInput));

// Safe asynchronous operations
const asyncResult = await fromPromise(fetch('https://api.example.com/data'));

Working with Results

import { 
    match, map, chain, recover, all, any,
    unwrapOr, unwrapOrElse
} from '@moon7/result';

// Pattern matching
const message = match(result, {
    success: value => `Got value: ${value}`,
    failure: error => `Error: ${error.message}`
});

// Transforming successful results
const doubled = map(result, x => x * 2);

// Chaining operations
const final = chain(result, value => {
    return someOtherOperationThatMightFail(value);
});

// Recovering from errors
const recovered = recover(result, error => {
    console.log(`Recovering from: ${error.message}`);
    return defaultValue;
});

// Working with multiple results
const combined = all([result1, result2, result3]); // Success only if ALL succeed
const any = any([result1, result2, result3]); // Success if ANY succeeds

Async Support

The library provides full support for asynchronous operations:

import { fromTryAsync, fromPromise } from '@moon7/result';

// Creating async results
const result = await fromTryAsync(async () => {
    const response = await fetch('https://api.example.com/data');
    return response.json();
});

// TypeScript narrows the type for safe value access
const value = isSuccess(result) ? result.value : defaultValue;

// Or use match pattern
const data = match(result, {
    success: value => value,
    failure: error => defaultValue
});

AsyncResult for Loading States

The library also provides an AsyncResult type that adds a third "pending" state to represent loading operations:

import { 
    AsyncResult, pending, success, failure, matchAsync
} from '@moon7/result';

// Component that displays user data with loading states
function UserProfile({ userId }: { userId: string }) {
    // State to hold the AsyncResult
    const [state, setState] = useState<AsyncResult<User, Error>>(pending);

    // Fetch user data when component mounts or userId changes
    useEffect(() => {
        async function fetchUser() {
            // Start with pending state
            setState(pending);
            
            try {
                // Simulate API call
                const response = await fetch(`/api/users/${userId}`);
                
                if (!response.ok) {
                    setState(failure(new Error("Error occurred")));
                    return;
                }
                
                const userData = await response.json();
                setState(success(userData));
            } catch (error) {
                setState(failure(error));
            }
        }
        
        fetchUser();
    }, [userId]);
    
    // Render different UI based on the AsyncResult state
    return (
        <div className="user-profile">
            {matchAsync(state, {
                pending: () => (
                    <div className="loading">Loading user...</div>
                ),
                success: (user) => (
                    <div className="user-data">
                        <h2>{user.name}</h2>
                        <p>Email: {user.email}</p>
                        <p>Role: {user.role}</p>
                    </div>
                ),
                failure: (error) => (
                    <div className="error">
                        <h2>Could not load user</h2>
                        <p>{error.message}</p>
                        <button onClick={() => fetchUser()}>Retry</button>
                    </div>
                )
            })}
        </div>
    );
}

Outcome Utilities

The library also provides a fromNodeCallback and liftOutcome utilities that directly works with Node.js-style callback functions:

import { fromNodeCallback, liftOutcome } from '@moon7/result';
import { readFile } from 'fs';

// Convert a Node.js callback function directly to a Promise<Result>
const fileResult = await fromNodeCallback(cb => 
    readFile("package.json", "utf8", cb)
);

// Now you can use all Result operations
if (isSuccess(fileResult)) {
    const content = fileResult.value;
    // Process content...
}

// If you have a function with multiple Outcome callbacks
multipleCallbacks(
    (err, val) => ...,
    (err, val) => ...
);

// Use liftOutcome to work with result values instead
multipleCallbacks(
    liftOutcome(result => ...),
    liftOutcome(result => ...)
);

This allows you to easily bridge Node.js callback-based APIs with the functional Result pattern.

Additional Utilities

The library also provides utilities for assertions and nullable handling:

import { must, strictMust, assert, assertNever } from '@moon7/result';

// Check for null or undefined
const value = must(maybeNull, "Value cannot be null");

// Type assertions
assert(condition, "Condition must be true");

// Exhaustive type checking with assertNever
type Shape = Circle | Square | Triangle;

function processShape(shape: Shape) {
    switch (shape.type) {
        case 'circle':
            return calculateCircleArea(shape);
        case 'square':
            return calculateSquareArea(shape);
        case 'triangle':
            return calculateTriangleArea(shape);
        default:
            // This ensures compiler error if you add a new shape type
            // but forget to handle it in this switch statement
            return assertNever(shape);
    }
}

The assertNever function is particularly valuable for exhaustiveness checking in TypeScript. If you add a new variant to the Shape type but forget to handle it in the switch statement, TypeScript will give you a compile-time error, preventing potential bugs.

Error Raising

The library provides convenient ways to throw errors as expressions:

import { raise } from '@moon7/result';

// Throw an error as an expression in a ternary
const value = condition ? computeValue() : raise(new Error("Condition failed"));

// Use in place of default values
const item = items.find(i => i.id === id) ?? raise(new Error(`Item ${id} not found`));

API Reference

Core Types

  • Result<V, E>: Union type of Success<V> and Failure<E>
  • Success<V>: Represents a successful operation with a value
  • Failure<E>: Represents a failed operation with an error
  • Maybe<T>: Union type of Some<T> and None for handling optional values
  • Some<T>: Represents a present value in a Maybe context
  • None: Represents absence of a value in a Maybe context
  • AsyncResult<V, E>: Represents a value that can be pending, success, or failure
  • Pending: Represents a pending/loading state
  • Outcome<V, E>: Tuple-based representation of [error, value] pairs

Type Guards

  • isSuccess<V, E>(result): Checks if a result is a Success<V>
  • isFailure<V, E>(result): Checks if a result is a Failure<E>
  • isSome<T>(maybe): Checks if a maybe is a Some<T>
  • isNone<T>(maybe): Checks if a maybe is None
  • isPending<V, E>(result): Checks if an async result is Pending
  • isResult<V, E>(result): Checks if something is a Result<V, E>
  • isAsyncResult<V, E>(result): Checks if something is an AsyncResult<V, E>

Constructors

  • success<V>(value): Creates a Success<V> result
  • failure<E>(error): Creates a Failure<E> result
  • some<T>(value): Creates a Some<T> maybe value
  • none: Constant representing None
  • pending: Constant representing the pending state

Unwrapping Functions

  • unwrap<V, E>(result): Extracts the value or throws the error
  • unwrapOr<V, E>(result, defaultValue): Extracts the value or returns a default
  • unwrapOr<V, E>(result): Extracts the value or returns undefined
  • unwrapOrElse<V, E>(result, fn): Extracts the value or computes a fallback

Error Recovery

  • recover<V, E>(result, fn): Transforms a failure into a success by recovering from the error

Result Creation

  • fromTry<V, E>(fn): Creates a result from a function that might throw
  • fromTryAsync<V, E>(fn): Creates a result from an async function that might throw
  • fromPromise<V, E>(promise): Creates a result from a promise
  • fromNullable<V, E>(value, error): Creates a result from a nullable value
  • fromNodeCallback<V, E>(fn): Creates a result from a Node.js style callback
  • fromOutcome<V, E>(outcome): Converts an Outcome<V, E> to a Result<V, E>
  • fromMaybe<T>(maybe): Converts a Maybe<T> to a Result<T, null>
  • liftOutcome<V, E>(cb): Converts a Result callback to a Node-style callback

Collection Operations

  • all<V, E>(results): Succeeds if all results succeed, fails on first failure
  • any<V, E>(results): Succeeds on first success, fails if all fail

Pattern Matching

  • match<V, E, T>(result, patterns): Applies success or failure function based on result
  • matchAsync<V, E, T>(result, patterns): Async version of match for AsyncResults

Transformations

  • map<V, U, E>(result, fn): Maps a success value, preserves failure
  • chain<V, U, E>(result, fn): Maps a success to another result, preserves failure

Utility Functions

  • must<T>(value, errorMessage?): Ensures a value is not null or undefined
  • strictMust<T>(value, errorMessage?): Ensures a value is not undefined
  • assert<T>(condition, message?): Throws if condition is false
  • assertNever(value): Used for exhaustive checks in switch statements
  • safely<T>(x, defaultValue): Safely executes a function returning a default on error
  • attempt<T>(x): Similar to safely but returns a Result instead
  • raise<E>(error?): Throws an error as an expression

Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

Related Libraries

The moon7 ecosystem includes several companion libraries that work well together:

License

MIT © Munir Hussin