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

@redchili/nothrow

v0.1.0

Published

Type-safe error handling library with Result pattern

Readme

@redchili/nothrow

Errors are values, not exceptions.

A lightweight TypeScript library that brings Go-style error handling to JavaScript/TypeScript. Instead of throwing exceptions that disrupt control flow, treat errors as explicit return values that must be handled.

Philosophy

In Go, error handling is explicit and visible:

result, err := doSomething()
if err != nil {
    return err
}

This approach has several advantages:

  • Explicit Control Flow: Errors don't invisibly jump up the call stack
  • Type Safety: Errors are part of the type signature
  • Force Handling: You can't accidentally ignore an error
  • Better Performance: No exception stack unwinding

@redchili/nothrow brings this philosophy to TypeScript with a minimal API surface.

Installation

npm install @redchili/nothrow
# or
bun install @redchili/nothrow

Usage

Basic Example

import { safe, isErr } from '@redchili/nothrow';

const result = safe(() => {
  return JSON.parse('{"valid": "json"}');
});

if (isErr(result)) {
  console.error('Parse failed:', result.reason);
  return;
}

// TypeScript knows result is the success type here
console.log(result.valid);

Async Operations

import { safeAsync, isErr } from '@redchili/nothrow';

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

if (isErr(result)) {
  console.error('Request failed:', result.reason);
  return;
}

console.log(result);

Custom Error Types

import { safe, isErr } from '@redchili/nothrow';

type DbError = { reason: 'DB_CONNECTION_FAILED' | 'DB_QUERY_ERROR'; details: string };

const result = safe<User[], DbError>(
  () => db.query('SELECT * FROM users'),
  (e) => ({
    reason: 'DB_QUERY_ERROR',
    details: (e as Error).message
  })
);

if (isErr(result)) {
  // result.reason is typed as 'DB_CONNECTION_FAILED' | 'DB_QUERY_ERROR'
  console.error(`Database error: ${result.reason}`, result.details);
  return;
}

// TypeScript knows result is User[] here
const users = result;

Manual Error Construction

import { ok, err, isErr } from '@redchili/nothrow';

function divide(a: number, b: number) {
  if (b === 0) {
    return err({ reason: 'DIVISION_BY_ZERO' });
  }
  return ok(a / b);
}

const result = divide(10, 2);
if (isErr(result)) {
  console.error('Cannot divide:', result.reason);
} else {
  console.log('Result:', result); // 5
}

Chaining Operations

import { safe, isErr } from '@redchili/nothrow';

function processUser(userId: string) {
  const user = safe(() => fetchUser(userId));
  if (isErr(user)) return user;

  const validated = safe(() => validateUser(user));
  if (isErr(validated)) return validated;

  const saved = safe(() => saveUser(validated));
  if (isErr(saved)) return saved;

  return ok(saved);
}

API

ok<T>(value: T): Result<T, E>

Wraps a successful value in a Result type.

err<E>(reason: E): Result<never, E & { stack: string }>

Creates an error result with automatic stack trace capture.

isErr<T, E>(result: Result<T, E>): result is Err<E>

Type guard to check if a result is an error.

isOk<T, E>(result: Result<T, E>): result is T

Type guard to check if a result is successful.

safe<T, E>(fn: () => T, mapError?: (e: unknown) => E): Result<T, E>

Executes a synchronous function and catches any thrown exceptions, returning a Result.

safeAsync<T, E>(fn: () => Promise<T>, mapError?: (e: unknown) => E): Promise<Result<T, E>>

Executes an async function and catches any thrown exceptions, returning a Promise of Result.

Why Not Try/Catch?

Traditional try/catch has several issues:

// ❌ Error handling is optional - easy to forget
function parseJson(text: string) {
  return JSON.parse(text); // Can throw, but type signature doesn't show it
}

// ❌ Error type is unknown
try {
  parseJson(input);
} catch (error) {
  // What is error? Who knows!
}

// ✅ With noThrow, errors are explicit
const result = safe(() => JSON.parse(input));
if (isErr(result)) {
  // TypeScript knows the error shape
  console.error(result.reason);
}

License

MIT