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

no-exceptions

v0.0.14

Published

[![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](LICENSE) [![npm version](https://img.shields.io/npm/v/no-exceptions.svg)](https://www.npmjs.com/package/no-exceptions)

Readme

no-exceptions

License: MIT npm version

A minimal and opinionated TypeScript implementation of the Result pattern for explicit and type-safe error handling, aiming to be an easy-to-adopt solution for any project.

Table of Contents

Description

no-exceptions is an implementation of the Result pattern - a design pattern for explicit, type-safe error handling originating in languages like Rust, Haskell, and Elm.

Unlike traditional methods where functions return null or throw exceptions to signify failure, the Result pattern wraps the outcome in a Result object. This object can either represent a successful outcome containing the expected data or an unsuccessful outcome with error information.

By making error states part of a function’s type signature and enforcing explicit handling of both success and failure, this approach leads to safer, more predictable code and consistent, visible error handling, reducing unhandled errors and unexpected crashes.


no-exceptions implements the Result pattern using two core classes:

  • Ok<T>: Represents a successful outcome and holds a value of type T.
  • Err<E>: Represents a failed outcome and holds an error of type E.

Both Ok and Err expose a rich set of identical methods, allowing you to transform, chain, and handle results in a fluent and type-safe way, without ever needing to unwrap the values.

These two classes are unified under the Result<T, E> type, which is simply a union: Ok<T> | Err<E>. This means any function returning a Result will always be explicit about both its success and failure possibilities.

Install

npm install no-exceptions
yarn add no-exceptions
pnpm add no-exceptions
bun add no-exceptions

API Reference

Core Types

Result<T, E>

A union type representing either a successful result (Ok<T>) or a failed result (Err<E>). This is the main type used throughout the library for error handling.

type Result<T, E> = Ok<T> | Err<E>;

Ok<T>

Represents a successful result containing a value of type T.

class Ok<T> {
  constructor(readonly value: T);
}

Err<E>

Represents a failed result containing an error of type E.

class Err<E> {
  constructor(readonly error: E);
}

ResultPromise<T, E>

A wrapper for Result that allows you to work with results asynchronously.

class ResultPromise<T, E> {
  constructor(promise: Promise<Result<T, E>>);
}

Utility Functions

ok<T>(value: T): Ok<T>

Creates a new Ok result with the given value.

const result = ok(42);
// result: Ok<number>

err<E>(error: E): Err<E>

Creates a new Err result with the given error.

const result = err("Something went wrong");
// result: Err<string>

attempt<T>(...): Result<T, Error> | ResultPromise<T, Error>

Executes a function or Promise and catches any errors, returning a Result or ResultPromise.

// sync
function attempt<T>(fn: () => T): Result<T, Error>;

// async
function attempt<T>(fn: () => Promise<T>): ResultPromise<T, Error>;

// promise
function attempt<T>(promise: Promise<T>): ResultPromise<T, Error>;

// executor (Promise constructor)
function attempt<T>(
  executor: (
    resolve: (value: T) => void,
    reject:  (error: unknown) => void
  ) => void,
): ResultPromise<T, Error>;

⚠️ Note: The executor overload requires the generic type parameter <T> to be explicitly specified.

const result = attempt(() => JSON.parse('{"valid": "json"}'));
// result: Result<any, Error>

const result = attempt(async () => fetch("/api/data"));
// result: ResultPromise<Response, Error>

const result = attempt(fetch("/api/data"));
// result: ResultPromise<Response, Error>

const result = attempt<string>((resolve, reject) => {
  setTimeout(() => resolve("success"), 1000);
});
// result: ResultPromise<string, Error>

Result Methods

isOk(): boolean

Checks if the result is an Ok variant.

const result = ok(42);
if (result.isOk()) {
  console.log(result.value); // 42
}

isErr(): boolean

Checks if the result is an Err variant.

const result = err("Something went wrong");
if (result.isErr()) {
  console.log(result.error); // "Something went wrong"
}

map<U>(fn: (value: T) => U): Result<U, E>

Transforms the success value if this is an Ok, otherwise returns the Err unchanged.

const result = ok(42);
const doubled = result.map((x) => x * 2);
// doubled: Ok<number> with value 84

mapErr<U>(fn: (error: E) => U): Result<T, U>

Transforms the error value if this is an Err, otherwise returns the Ok unchanged.

const result = err("network error");
const formatted = result.mapErr((err) => `Error: ${err}`);
// formatted: Err<string> with error "Error: network error"

and<U, V>(fn: (value: T) => Result<U, V>): Result<U, E | V>

Chains another Result-returning function if this is an Ok, otherwise returns the Err unchanged.

const result = ok(42);
const processed = result.and((x) => ok(x.toString()));
// processed: Ok<string> with value "42"

andErr<U, V>(fn: (error: E) => Result<U, V>): Result<T | U, V>

Chains another Result-returning function if this is an Err, otherwise returns the Ok unchanged.

const result = err("network error");
const recovered = result.andErr((err) => ok(`Recovered from: ${err}`));
// recovered: Ok<string> with value "Recovered from: network error"

tap(fn: (value: T) => unknown): Result<T, E>

Executes a side effect on the success value and returns the original Result unchanged.

const result = ok(42);
const logged = result.tap((x) => console.log(`Got value: ${x}`));
// Logs: Got value: 42
// logged: Ok<number> with value 42

tapErr(fn: (error: E) => unknown): Result<T, E>

Executes a side effect on the error value and returns the original Result unchanged.

const result = err("Something went wrong");
const logged = result.tapErr((err) => console.log(`Error: ${err}`));
// Logs: Error: Something went wrong
// logged: Err<string> with error "Something went wrong"

unwrap<V>(fallback?: V): T | V

⚠️ WARNING: This method can throw and should be used with extreme care!

Returns the contained Ok value, or a provided default if this is an Err.

const result = ok(42);
const value = result.unwrap();
// value: 42

const errResult = err("error");
const fallback = errResult.unwrap("default");
// fallback: "default"

const errResult = err("error");
const fallback = errResult.unwrap();
// throws an Error

attempt<U>(fn: (value: T) => U): Result<U, E | Error>

Safely executes a function on the success value, catching any thrown errors.

const result = ok('{"valid": "json"}');
const parsed = result.attempt((str) => JSON.parse(str));
// parsed: Ok<{valid: string}> or Err<Error>

async: ResultPromise<T, E>

Converts the Result to a ResultPromise for async operations.

const result = ok(42);
const asyncResult = result.async
  .map((x) => fetch(`/api/data/${x}`))
  .and((response) => response.json());
// asyncResult: ResultPromise<any, Error>

ResultPromise.create<T, E>(result: Promise<Result<T, E>>): ResultPromise<T, E>

Creates a ResultPromise from a Promise that resolves to a Result.

const promise = fetch("/api/data").then((response) =>
  response.ok ? ok(response) : err("Request failed"),
);
const resultPromise = ResultPromise.create(promise);
// resultPromise: ResultPromise<Response, string>

ResultPromise.createFunction<T, E>(fn: (...args: any[]) => Promise<Result<T, E>>): (...args: any[]) => ResultPromise<T, E>

Utility for creating async Result functions.

const asyncFn = async (id: number) => {
  const response = await fetch(`/api/users/${id}`);
  return response.ok ? ok(await response.json()) : err("Not found");
};

const wrappedFn = ResultPromise.createFunction(asyncFn);
const result = wrappedFn(123);
// result: ResultPromise<User, string>

License

MIT