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

@openally/result

v3.1.0

Published

Another inspired Rust's Result implementation.

Readme

Result<T, E> lets you encode functions that may fail without throwing: it forces callers to explicitly handle both the success (Ok<T>) and failure (Err<E>) cases instead of relying on try/catch. Option<T> does the same for values that may or may not be present (Some<T> / None), avoiding null/undefined checks scattered across the codebase.

Requirements

Getting Started

This package is available in the Node Package Repository and can be easily installed with npm or yarn.

$ npm i @openally/result
# or
$ yarn add @openally/result

Usage example

import fs from "node:fs";
import {
  Ok, Err, Option, wrap, type Result
} from "@openally/result";

interface Config {
  host: string;
  port: number;
}

function readConfigFile(
  path: string
): Result<string, string> {
  return fs.existsSync(path) ?
    Ok(fs.readFileSync(path, "utf8")) :
    Err(`config file not found at "${path}"`);
}

function parseJSON(
  raw: string
): Result<Record<string, unknown>, string> {
  return wrap<Record<string, unknown>, Error>(() => JSON.parse(raw))
    .mapErr((error) => `invalid JSON: ${error.message}`);
}

function toConfig(
  record: Record<string, unknown>
): Result<Config, string> {
  const { host, port } = record;

  return typeof host === "string" && typeof port === "number" ?
    Ok({ host, port }) :
    Err("config must have a string `host` and a numeric `port`");
}

function configFromEnv(): Result<Config, string> {
  return Option.from(process.env.HOST)
    .andThen((host) => {
      return Option.from(process.env.PORT)
        .map((port) => ({ host, port: Number(port) }));
    })
    .toResult("no config file and no HOST/PORT environment variables set");
}

function loadConfig(path: string): Result<Config, string> {
  return readConfigFile(path)
    .andThen(parseJSON)
    .andTee((record) => console.log("loaded raw config:", record))
    .andThen(toConfig)
    .orElse(() => configFromEnv());
}

loadConfig("config.json").match(
  (config) => console.log(`ready on ${config.host}:${config.port}`),
  (error) => {
    console.error(`failed to load config: ${error}`);
    process.exit(1);
  }
);

Table of contents

Result API

Constructors: Ok, Err

function Ok<T>(value: T): OkImpl<T>;
function Err<E>(error: E): ErrImpl<E>;

Build a successful (Ok) or failed (Err) Result.

const good = Ok(1);
const bad = Err("oops");

isOk, isErr

isOk(): boolean;
isErr(): boolean;

Narrow a Result<T, E> to its Ok or Err variant. Equivalent to reading the .ok/.err boolean properties directly, provided for API parity/readability in conditionals.

const result = Ok(1);

result.isOk(); // true
result.isErr(); // false

unwrap

Get the value if Ok, throw if Err.

Ok(1).unwrap(); // 1
Err("oops").unwrap(); // Error: Tried to unwrap Error: oops

unwrapOr

Get the value if Ok, fallback to a default value if Err (instead of throwing).

Ok(1).unwrapOr(5); // 1
Err("oops").unwrapOr(5); // 5

unwrapOrElse

Same as unwrapOr but using a lazy function for the default value.

Ok(1).unwrapOrElse(() => 5); // 1
Err("oops").unwrapOrElse(() => 5); // 5

safeUnwrap

Same as unwrap but only available on Ok (useful for type narrowing when you already know the Result is Ok).

map

Map the value for Ok. Does nothing on Err (use mapErr instead).

Ok(1)
  .map((v) => v + 1)
  .unwrap(); // 2

mapErr

Map the value for Err. Does nothing on Ok (use map instead).

Err(new Error("oops"))
  .mapErr((cause) => new Error("oh no", { cause }))
  .unwrap();

mapOr

Map and unwrap in one step:

  • Use the default value for Err
  • Use the mapper for Ok
Ok(1)
  .mapOr(1, (val) => val * 2); // 2

Err(new Error("oops"))
  .mapOr(1, (val) => val * 2); // 1

mapOrElse

Same as mapOr but uses a callback (fed with the error) for the default value.

Err(new Error("oops"))
  .mapOrElse(
    (err) => err.message,
    (val) => val * 2
  ); // oops

andThen

Similar to Promise.then, chain a Result-returning computation on the Ok value. Short-circuits on Err.

Ok(1)
  .andThen((value) => Ok(value + 1))
  .unwrap(); // 2

This can also be used to turn an Ok into an Err.

orElse

The error-side counterpart of andThen: recover from an Err by returning a new Result. Does nothing on Ok.

Err("oops")
  .orElse(() => Ok(5))
  .unwrap(); // 5

Ok(1)
  .orElse(() => Ok(5))
  .unwrap(); // 1 (untouched)

andTee

Run a side effect (e.g. logging) on the Ok value without changing the Result. Does nothing on Err.

Ok(1)
  .andTee((val) => console.log(`got ${val}`))
  .unwrap(); // 1, and logs "got 1"

orTee

The Err counterpart of andTee: run a side effect on the error without changing the Result. Does nothing on Ok.

Err("oops")
  .orTee((err) => console.error(err)); // logs "oops", Result untouched

andThrough

Run a Result-returning validation on the Ok value, keeping the original Ok value if the validation succeeds, or propagating the new Err if it fails.

Ok(1)
  .andThrough((val) => val > 0 ? Ok(val) : Err("must be positive"))
  .unwrap(); // 1

match

Handle both the Ok and Err cases with dedicated callbacks and return a single value — no need to branch on .ok/.err yourself.

const message = readFile("test.txt").match(
  (content) => `read ${content.length} bytes`,
  (error) => `failed: ${error}`
);

stack (Err only)

Return the Err stack trace (captured at creation time, not available on Ok).

const _e = Err(new Error());
console.log(_e.stack);

Option API

Constructors: Some, None

function Some<T>(value: T): SomeImpl<T>;
const None: NoneImpl;
const present = Some(1);
const absent = None;

Option.from

Collapse a value that may be null/undefined into an Option, without needing to import a separate utility.

function Option.from<T>(val: T | null | undefined): Option<NonNullable<T>>;
Option.from(5); // Some(5)
Option.from(null); // None
Option.from(undefined); // None

unwrap, unwrapOr, unwrapOrElse, safeUnwrap, expect

Same semantics as their Result counterparts, but for presence/absence instead of success/failure. expect(msg) is an alias of unwrap() (kept for Rust-API familiarity).

Some(1).unwrap(); // 1
None.unwrap(); // Error: Tried to unwrap None
None.unwrapOr(5); // 5
None.unwrapOrElse(() => 5); // 5

map, mapOr, mapOrElse

Same semantics as their Result counterparts.

Some(1).map((v) => v + 1).unwrap(); // 2
None.mapOr(0, (v) => v + 1); // 0

andThen

Chain an Option-returning computation on the value. Short-circuits on None.

Some(1).andThen((v) => (v > 0 ? Some(v) : None));

toResult

Convert an Option<T> into a Result<T, E>, using the given error value when None.

Some(1).toResult("missing"); // Ok(1)
None.toResult("missing"); // Err("missing")

Utilities

wrap

Wrap an operation that may throw (try/catch style) into a Result.

function wrap<T, E = unknown>(op: () => T): Result<T, E>;
const result = wrap(() => JSON.parse(input));

wrapAsync

Same as wrap but for an async operation, resolving to Promise<Result<T, E>>.

function wrapAsync<T, E = unknown>(op: () => Promise<T>): Promise<Result<T, E>>;
const result = await wrapAsync(() => fetch(url).then((r) => r.json()));

isResult

Type guard checking whether a value is a Result (either Ok or Err).

function isResult<T = any, E = any>(val: unknown): val is Result<T, E>;

combine

Combine a tuple/array of Results into a single Result. Short-circuits on the first Err encountered; the resulting Ok value preserves each input's type at its tuple position.

function combine<T extends readonly Result<any, any>[]>(
  results: T
): Result<{ [K in keyof T]: InferOkTypes<T[K]> }, InferErrTypes<T[number]>>;
combine([Ok(1), Ok("foo"), Ok(true)]); // Ok([1, "foo", true])
combine([Ok(1), Err("oops"), Err("never reached")]); // Err("oops")

combineWithAllErrors

Same as combine, but collects every encountered Err instead of short-circuiting on the first one.

function combineWithAllErrors<T extends readonly Result<any, any>[]>(
  results: T
): Result<{ [K in keyof T]: InferOkTypes<T[K]> }, InferErrTypes<T[number]>[]>;
combineWithAllErrors([Ok(1), Err("first"), Err("second")]); // Err(["first", "second"])

License

MIT