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

@try-error/core

v0.0.1

Published

Lightweight, progressive, type-safe error handling for TypeScript

Readme

try-error

Lightweight, progressive, type-safe error handling for TypeScript

npm version npm downloads Bundle Size gzip size TypeScript PRs Welcome License: MIT npm code style: prettier Maintenance Dependencies

⚠️ Alpha Version: This library is currently in alpha and APIs may change. Not recommended for production use yet.

Why try-error?

Traditional error handling in JavaScript forces you to choose between:

  • try/catch blocks: Clunky syntax, no type safety, hidden control flow
  • Functional libraries: Heavy abstractions, steep learning curve, large bundle size

try-error provides a middle ground:

  • Errors as values - Explicit error handling without exceptions
  • Zero overhead - Success values are returned directly
  • Type safe - Full TypeScript support with type inference
  • Progressive - Start simple, add complexity as needed
  • Tiny - 4.7KB minified + gzipped (core), 3.1KB (React)
  • Familiar - Looks and feels like JavaScript

Installation

npm install try-error
# or
yarn add try-error
# or
pnpm add try-error

Quick Start

import { trySync, tryAsync, isTryError } from "try-error";

// Wrap synchronous operations
const result = trySync(() => JSON.parse(jsonString));
if (isTryError(result)) {
  console.error("Parse failed:", result.message);
} else {
  console.log("Parsed:", result); // Type-safe!
}

// Wrap async operations
const data = await tryAsync(async () => {
  const response = await fetch("/api/data");
  return response.json();
});

if (isTryError(data)) {
  console.error("Request failed:", data.message);
} else {
  console.log("Data:", data); // Type-safe!
}

Core Concepts

1. Errors as Values

Instead of throwing exceptions, operations return either a success value or an error object:

// Returns either User or TryError
const user = trySync(() => validateUser(input));

if (isTryError(user)) {
  // Handle error case
  console.error(user.message);
} else {
  // Use the user (fully typed!)
  console.log(user.name);
}

2. Rich Error Context

Every error includes debugging information automatically:

const result = trySync(() => JSON.parse("invalid"));
if (isTryError(result)) {
  console.log(result.type); // "SyntaxError"
  console.log(result.message); // "Unexpected token i in JSON"
  console.log(result.source); // "app.ts:42:15"
  console.log(result.timestamp); // 1640995200000
  console.log(result.stack); // Stack trace (dev only)
}

3. Zero Overhead Success Path

Success values are returned directly without wrapping:

const result = trySync(() => 2 + 2);
// result === 4 (not wrapped!)

API Overview

Basic Operations

// Synchronous operations
trySync(() => riskyOperation());
trySyncTuple(() => riskyOperation()); // Go-style [value, error]

// Asynchronous operations
await tryAsync(async () => await fetch("/api"));
await tryAsyncTuple(async () => await fetch("/api"));

// Type guards
isTryError(result); // Check if error
isOk(result); // Check if success
isErr(result); // Alias for isTryError

Transformations

// Transform success values
const upper = tryMap(
  trySync(() => getUserName()),
  (name) => name.toUpperCase()
);

// Chain operations
const result = tryChain(
  trySync(() => parseJSON(input)),
  (parsed) => trySync(() => validate(parsed))
);

Error Recovery

// Provide defaults
const value = unwrapOr(result, defaultValue);

// Try multiple sources
const data = await tryAnyAsync([
  tryAsync(() => fetchFromAPI()),
  tryAsync(() => fetchFromCache()),
  tryAsync(() => fetchFromDisk()),
]);

// Retry with backoff
const response = await retry(() => tryAsync(() => fetch("/api/flaky")), {
  attempts: 3,
  baseDelay: 1000,
});

Advanced Features

// Add timeout to any operation
const result = await withTimeout(
  tryAsync(() => slowOperation()),
  5000 // 5 seconds
);

// Process multiple operations
const results = await tryAllAsync([
  tryAsync(() => fetch("/api/users")),
  tryAsync(() => fetch("/api/posts")),
  tryAsync(() => fetch("/api/comments")),
]);

React Integration

npm install @try-error/react
import { useTry } from "@try-error/react";

function UserProfile({ userId }) {
  const {
    data: user,
    error,
    isLoading,
    execute,
  } = useTry(() => fetchUser(userId), { immediate: true, deps: [userId] });

  if (isLoading) return <div>Loading...</div>;
  if (error) return <div>Error: {error.message}</div>;
  return <div>Welcome, {user.name}!</div>;
}

Comparison with Alternatives

| Feature | try-error | fp-ts | neverthrow | native try/catch | | -------------- | --------- | -------- | ---------- | ---------------- | | Type Safety | ✅ Full | ✅ Full | ✅ Full | ❌ None | | Bundle Size | 4.7KB | ~50KB | ~12KB | 0KB | | Learning Curve | Low | High | Medium | Low | | Zero Overhead | ✅ Yes | ❌ No | ❌ No | ✅ Yes | | Async Support | ✅ Yes | ✅ Yes | ✅ Yes | ✅ Yes | | Error Context | ✅ Rich | ❌ Basic | ❌ Basic | ❌ Basic |

Examples

API Client

class APIClient {
  async getUser(id: string) {
    return tryAsync(async () => {
      const response = await fetch(`/api/users/${id}`);
      if (!response.ok) {
        throw new Error(`HTTP ${response.status}`);
      }
      return response.json();
    });
  }
}

// Usage
const client = new APIClient();
const user = await client.getUser("123");
if (isTryError(user)) {
  console.error("Failed to fetch user:", user.message);
} else {
  console.log("User:", user.name);
}

Form Validation

function validateEmail(email: string) {
  return trySync(() => {
    if (!email.includes("@")) {
      throw new Error("Invalid email format");
    }
    return email.toLowerCase();
  });
}

const result = validateEmail(userInput);
if (isTryError(result)) {
  setError(result.message);
} else {
  setEmail(result);
}

File Processing

async function processFile(path: string) {
  // Read file
  const content = await tryAsync(() => fs.readFile(path, "utf8"));
  if (isTryError(content)) return content;

  // Parse JSON
  const data = trySync(() => JSON.parse(content));
  if (isTryError(data)) return data;

  // Validate data
  const validated = trySync(() => validateSchema(data));
  if (isTryError(validated)) return validated;

  return validated;
}

Contributing

We welcome contributions! Please see our Contributing Guide for details.

License

MIT © Daniel Johnson

Links