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

gw-result

v0.3.0

Published

Tiny TypeScript Result helpers with inferred error contracts.

Readme

gw-result

Tiny TypeScript helpers for returning success and failure as explicit values.

gw-result gives you a small Result union, helpers for wrapping throwing functions, typed application exceptions, and a fetch wrapper that returns a result instead of throwing.

  • Zero runtime dependencies
  • TypeScript-first API with discriminated unions
  • Works with synchronous and asynchronous functions
  • Exports ESM and CommonJS builds

Installation

npm install gw-result
pnpm add gw-result
yarn add gw-result

Quick Start

import { err, ok } from "gw-result";

function parsePort(value: string) {
  if (!value) {
    return err("EMPTY");
  }

  const port = Number(value);

  if (!Number.isInteger(port)) {
    return err("INVALID");
  }

  return ok(port);
}

const result = parsePort("3000");

if (result.isOk) {
  console.log(result.value);
} else {
  console.error(result.error);
}

isOk and isErr are boolean discriminants, so TypeScript narrows the result for you inside each branch.

Inferred Error Contracts

The most useful part of gw-result is that small functions do not need return type annotations. Function authors define the error contract by returning literal err(...) values, and callers get that contract from TypeScript without writing a Result<...> type themselves.

import { err, ok } from "gw-result";

function loadConfig(raw?: { port?: number }) {
  if (!raw) {
    return err("EMPTY_CONFIG");
  }

  if (typeof raw.port !== "number") {
    return err("MISSING_PORT");
  }

  return ok({ port: raw.port });
}

const result = loadConfig({ port: 3000 });

if (result.isErr) {
  result.error;
  // ^? "EMPTY_CONFIG" | "MISSING_PORT"
}

Primitive error values keep their literal types, so err("EMPTY_CONFIG") is an Err<"EMPTY_CONFIG">, not just Err<string>.

Result

type Result<T = void, TError = Error> = Ok<T> | Err<TError>;

type Ok<T> = {
  isOk: true;
  isErr: false;
  value: T;
};

type Err<T> = {
  isOk: false;
  isErr: true;
  error: T;
};

Create success and error values with ok and err:

import { err, ok } from "gw-result";

const created = ok({ id: "user_123" });
const failed = err(new Error("User already exists"));

Primitive error values keep their literal type:

import { err, ok } from "gw-result";

function findUser(id: string) {
  if (!id) {
    return err("MISSING_ID");
  }

  return ok({ id });
}

const result = findUser("user_123");

Use ok() without an argument for operations that only need to signal success:

import { ok } from "gw-result";

function saveSettings() {
  // Save settings here.
  return ok();
}

Wrapping Functions

Use resultFrom when you want to convert thrown errors or rejected promises into an Err.

import { resultFrom } from "gw-result";

const parsed = resultFrom(JSON.parse, '{"enabled":true}');

if (parsed.isErr) {
  console.error(parsed.error);
}

It also works with async functions:

import { resultFrom } from "gw-result";

async function loadUser(id: string) {
  const response = await fetch(`/api/users/${id}`);
  return response.json();
}

const userResult = await resultFrom(loadUser, "user_123");

if (userResult.isErr) {
  console.error(userResult.error);
  return;
}

console.log(userResult.value);

The error value is whatever the wrapped function throws or rejects with. Throwing Error instances gives the best runtime ergonomics, but JavaScript can throw anything, so resultFrom types caught errors as unknown by default.

When you know the value and error types at a boundary, pass them explicitly:

import { resultFrom } from "gw-result";

type Config = {
  enabled: boolean;
};

const parsed = resultFrom<Config, SyntaxError>(() =>
  JSON.parse('{"enabled":true}') as Config,
);

resultFrom treats any PromiseLike value as async, not only native Promise instances.

Exceptions

Use Exception when your application errors should carry a stable code and a human-readable message.

import { exception, ok } from "gw-result";

type User = {
  id: string;
  role: "admin" | "member";
};

function requireAdmin(user?: User) {
  if (!user) {
    return exception("UNAUTHORIZED", "Sign in is required.");
  }

  if (user.role !== "admin") {
    return exception("FORBIDDEN", "You do not have access.");
  }

  return ok(user);
}

exception(code, message) returns an Err<Exception<TCode>>:

const result = exception("VALIDATION_FAILED", "Email is required.");

if (result.isErr) {
  console.log(result.error.code);
  console.log(result.error.message);
}

Fetch

fetchWithResult wraps the platform fetch API and returns a result.

import { fetchWithResult } from "gw-result";

const result = await fetchWithResult("/api/users");

if (result.isErr) {
  alert(result.error.message);
  return;
}

const users = await result.value.json();
console.log(users);

Behavior:

  • Network errors become Err<Error>.
  • Successful HTTP responses become Ok<Response>.
  • Non-2xx responses become Err<HttpException<string>>.
  • For failed HTTP responses, HttpException.code and HttpException.message are derived from a JSON { code, message } body when present.
  • If no JSON message exists, HttpException.message falls back to body text, statusText, or the HTTP status.
  • The HttpException response is available as error.response for status, headers, and body inspection.

When you need HTTP details, import HttpException and narrow the error:

import { fetchWithResult, HttpException } from "gw-result";

const result = await fetchWithResult("/api/users");

if (result.isErr && result.error instanceof HttpException) {
  console.log(result.error.response.status);
}

You can also parse an HTTP exception response directly:

import { HttpException } from "gw-result";

const error = await HttpException.fromResponse<"NOT_FOUND">(response);

fetchWithResult requires a runtime that provides global fetch, such as modern browsers, Node.js 18+, Bun, or Deno.

API Reference

| Export | Description | | --- | --- | | Result<T, TError> | Union of Ok<T> and Err<TError>. | | Ok<T> | Successful result shape. | | Err<T> | Failed result shape. | | ok(value?) | Creates an Ok result. | | err(error?) | Creates an Err result and preserves primitive error literals. | | resultFrom(fn, ...args) | Wraps a sync, async, or PromiseLike function in a Result; caught errors default to unknown. | | Exception<TCode> | Error class with code and message. | | Ex<TCode> | Alias for Err<Exception<TCode>>. | | exception(code, message) | Creates an exception result. | | HttpException<TCode> | HTTP error class with code, message, and response. | | HttpEx<TCode> | Alias for Err<HttpException<TCode>>. | | httpException(response, code?) | Creates an HTTP exception result with response-derived code and message. | | HttpException.fromResponse(response, code?) | Creates an HTTP exception from a response body. | | fetchWithResult(...args) | Fetch wrapper that returns Ok<Response> or Err. |

Development

npm install
npm run build
npm test

The package is built with tsup and emits type declarations to dist.

License

MIT