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 🙏

© 2025 – Pkg Stats / Ryan Hefner

resultant.js

v2.0.0

Published

A JavaScript library for handling results similar to Go and Rust.

Readme

resultant.js

resultant.js is a JavaScript/TypeScript library designed to bring Go-style error handling (goify) and Rust-style Result and Option enums (rustify) into the JavaScript ecosystem. It provides a more expressive, safer, and functional approach to handling errors and optional values, helping to reduce uncaught exceptions and null/undefined-related bugs.


Core Concepts

Go-Style Error Handling (goify)

Inspired by Go's multi-return error handling pattern, the goify functions return a tuple [result, error], where result is the successful return value of the operation and error is an error object if the operation fails. This allows the caller to explicitly handle both success and failure scenarios without relying on try-catch blocks.

Rust-Style Error Handling (rustify)

Drawing inspiration from Rust's Result<T, E> and Option<T> enums, the rustify module provides SafeResult<T> and Option<T> classes. These classes offer a rich set of methods to safely handle operations that might succeed or fail, and values that might be present or absent. This mechanism encourages explicit error handling and null-checking, thereby improving code robustness and readability.


Installation

You can install resultant.js using npm or yarn: Bash

npm install resultant.js
# or
yarn add resultant.js

Usage

Go-Style Error Handling (goify)

Use the goify and goifySync functions to wrap your asynchronous or synchronous operations. TypeScript

import { goify, goifySync } from 'resultant.js/goify';

// Async operation example
const fetchData = async (shouldFail: boolean): Promise<string> => {
    return new Promise((resolve, reject) => {
        setTimeout(() => {
            if (shouldFail) {
                reject(new Error("Failed to load data!"));
            } else {
                resolve("Data loaded successfully!");
            }
        }, 100);
    });
};

async function handleAsyncOperation() {
    // Success case
    const [data, error] = await goify(() => fetchData(false));
    if (error) {
        console.error("Async operation failed:", error.message);
    } else {
        console.log("Async operation successful:", data); // Output: Data loaded successfully!
    }

    // Failure case
    const [data2, error2] = await goify(() => fetchData(true));
    if (error2) {
        console.error("Async operation failed:", error2.message); // Output: Failed to load data!
    } else {
        console.log("Async operation successful:", data2);
    }
}

// Sync operation example
const divide = (a: number, b: number): number => {
    if (b === 0) {
        throw new Error("Division by zero");
    }
    return a / b;
};

function handleSyncOperation() {
    // Success case
    const [result, err] = goifySync(() => divide(10, 2));
    if (err) {
        console.error("Sync operation failed:", err.message);
    } else {
        console.log("Sync operation successful:", result); // Output: 5
    }

    // Failure case
    const [result2, err2] = goifySync(() => divide(10, 0));
    if (err2) {
        console.error("Sync operation failed:", err2.message); // Output: Division by zero
    } else {
        console.log("Sync operation successful:", result2);
    }
}

handleAsyncOperation();
handleSyncOperation();

Rust-Style Error Handling (rustify)

SafeResult<T> and Option<T> provide a richer, more functional API for handling fallible operations and optional values.

SafeResult<T>

SafeResult<T> is used to represent an operation that may either succeed (Ok) or fail (Err). TypeScript

import { buildSafeResult, SafeResult } from 'resultant.js/rustify';

// Simulate an async operation that might succeed or fail
const performDatabaseQuery = async (userId: string): Promise<string> => {
    return new Promise((resolve, reject) => {
        setTimeout(() => {
            if (userId === "invalid") {
                reject(new Error("Invalid user ID"));
            } else if (userId === "admin") {
                resolve("Admin data");
            } else {
                resolve(`Data for user ${userId}`);
            }
        }, 150);
    });
};

async function processUser(userId: string) {
    const result: SafeResult<string> = await buildSafeResult(() => performDatabaseQuery(userId));

    if (result.isOk()) {
        console.log(`Query successful: ${result.unwrap()}`);
    } else {
        console.error(`Query failed: ${result.unwrapErr().message}`);
    }

    // More functional approach
    const processedData = result
        .map(data => data.toUpperCase()) // If Ok, transform the value to uppercase
        .unwrapOr("Default data"); // If Err, provide a default value

    console.log(`Processed data: ${processedData}`);

    // Chaining operations with andThen
    const chainedResult = await buildSafeResult(() => performDatabaseQuery("admin"))
        .andThen(value => {
            console.log(`First step successful, value: ${value}`);
            return new SafeResult({ value: `Transformed: ${value}` }); // Return a new SafeResult
        });

    if (chainedResult.isOk()) {
        console.log(`Chained operation successful: ${chainedResult.unwrap()}`);
    } else {
        console.error(`Chained operation failed: ${chainedResult.unwrapErr().message}`);
    }
}

processUser("user123");
processUser("invalid");
processUser("admin");

Option<T>

Option<T> is used to represent a value that may or may not be present (Some or None). This helps eliminate the need for null or undefined checks. TypeScript

import { Some, None, SafeOption } from 'resultant.js/rustify';

function getUserName(userId: number): SafeOption<string> {
    const users: { [key: number]: string } = {
        1: "John Doe",
        2: "Jane Smith",
        3: "Peter Jones",
    };

    const name = users[userId];
    return name ? Some(name) : None();
}

function displayUserName(userId: number) {
    const userNameOption = getUserName(userId);

    if (userNameOption.isSome()) {
        console.log(`Found user name: ${userNameOption.unwrap()}`);
    } else {
        console.log(`User name not found for ID: ${userId}`);
    }

    // Using map to transform the value
    const greeting = userNameOption.map(name => `Hello, ${name}!`).unwrapOr("Hello, stranger!");
    console.log(greeting);

    // Using andThen for chained optional operations
    const userEmailOption = userNameOption.andThen(name => {
        if (name === "John Doe") {
            return Some("[email protected]");
        }
        return None();
    });

    if (userEmailOption.isSome()) {
        console.log(`John Doe's email is: ${userEmailOption.unwrap()}`);
    } else {
        console.log("Email not found.");
    }
}

displayUserName(1);
displayUserName(4);
displayUserName(2);

match Functions

The match function allows you to convert an Option or SafeResult into a GoifyResult ([value, error]) when you need to switch to Go-style error handling. TypeScript

import { match, matchAsync, SafeResult, Option, Some, None, buildSafeResult } from 'resultant.js/rustify';

// Using match with SafeResult
async function processResult(shouldSucceed: boolean) {
    const myResult = await buildSafeResult(async () => {
        if (shouldSucceed) {
            return "Operation successful!";
        }
        throw new Error("Operation failed!");
    });

    const [value, error] = match(myResult);

    if (error) {
        console.error(`Match (Result) error: ${error.message}`);
    } else {
        console.log(`Match (Result) success: ${value}`);
    }
}

// Using match with Option
function processOption(hasValue: boolean) {
    const myOption = hasValue ? Some("Option has a value") : None<string>();

    const [value, error] = match(myOption);

    if (error) {
        console.error(`Match (Option) error: ${error.message}`);
    } else {
        console.log(`Match (Option) success: ${value}`);
    }
}

// Using matchAsync with Promise<Option | SafeResult>
async function processAsyncMatch(type: 'option' | 'result', succeed: boolean) {
    let promiseToMatch: Promise<Option<string> | SafeResult<string>>;

    if (type === 'option') {
        promiseToMatch = Promise.resolve(succeed ? Some("Option value from Promise") : None<string>());
    } else {
        promiseToMatch = buildSafeResult(async () => {
            if (succeed) {
                return "SafeResult value from Promise";
            }
            throw new Error("SafeResult error from Promise");
        });
    }

    const [value, error] = await matchAsync(promiseToMatch);

    if (error) {
        console.error(`Match Async (${type}) error: ${error.message}`);
    } else {
        console.log(`Match Async (${type}) success: ${value}`);
    }
}

processResult(true);
processResult(false);
processOption(true);
processOption(false);
processAsyncMatch('option', true);
processAsyncMatch('option', false);
processAsyncMatch('result', true);
processAsyncMatch('result', false);