@dliv/try-catch v1.0.1
try-catch
Treat errors as values like Go, Rust, React hooks, etc.
import { tryCatch } from '@dliv/try-catch';
// Using array destructuring (Go-style)
async function fetchUserWithArray(id: string) {
    const [user, err] = await tryCatch(fetchUserFromAPI(id));
    if (err) {
        console.error('Failed to fetch user:', err);
        return null;
    }
    return user;
}
// Using object destructuring
async function fetchUserWithObject(id: string) {
    const { data, error } = await tryCatch(fetchUserFromAPI(id));
    if (error) {
        console.error('Failed to fetch user:', error);
        return null;
    }
    return data;
}Yes: that one method is a mind reader.
Install
npm i @dliv/try-catchBenefits
- ✅ Keeps your happy path unindented and pairs well with guard clauses
 - ✅ Dual access pattern (array destructuring or object properties)
 - ✅ Simple: no dependencies, less than 100 LOC, 100% branch coverage, copy-pastable single-file
 - ✅ Type Safety and Runtime Safety - the 
erroris always an instance ofError 
Error Handling Comparison
Traditional try/catch
With a traditional try ... catch you have a choice between losing context around what
threw or lots of boilerplate wrapping individual calls.
async function fetchUserData(userId) {
    try {
        const response = await fetch(`/api/users/${userId}`);
        if (!response.ok) {
            throw response;
        }
        return await response.json();
    } catch (error) {
        // what threw? hopefully `error` is detailed (but it might not even be an Error)
        console.error('Error:', error);
        return null;
    }
}With try-catch
async function fetchUserData(userId) {
    const [response] = await tryCatch(fetch(`/api/users/${userId}`));
    const [json] = await tryCatch(response?.ok ? response.json() : null);
    return json;
}Or if you need fine grained error handling
async function fetchUserData(userId) {
    const [response, fetchError] = await tryCatch(fetch(`/api/users/${userId}`));
    if (fetchError) {
        console.error('Fetch error:', fetchError);
        return null;
    }
    if (!response.ok) {
        console.error('Response not okay:', response.status);
        return null;
    }
    const [json, jsonError] = await tryCatch(response.json());
    if (jsonError) {
        console.error('JSON parsing error:', jsonError);
        return null;
    }
    return json;
}Inspiration
- The errors as values approach in Go and Rust
 - Popular React libraries like this TanStack example: 
const { status, data, error, isFetching } = usePosts() - YouTube videos by AirShip and Theo
 - LoDash's attempt to do this for sync code (comparable to our 
tryCatchSync) 
API
tryCatch<T>(val: Awaitable<T>): Promise<ResultPair<T>>
Accepts a value, Promise, or thenable and returns a Promise containing a result pair / struct.
// With Promise
const [data, error] = await tryCatch(fetch('/api/data'));
// With direct value (automatically wrapped in a resolved Promise)
const [data, error] = await tryCatch(42);tryCatchSync<T>(val: T | (() => T)): ResultPair<T>
Synchronous version that accepts a value or function and returns a result pair immediately.
// With function that might throw
const [data, error] = tryCatchSync(() => JSON.parse(jsonString));
// With direct value
const [data, error] = tryCatchSync(42);Return Type: ResultPair<T>
The return value can be accessed in two ways:
- Array destructuring: 
const [data, error] = await tryCatch(...) - Object properties: 
const { data, error } = await tryCatch(...) 
If successful:
datacontains the returned valueerrorisnull
If an error occurs:
dataisnullerrorcontains the Error object (non-Error values are wrapped in an Error with the original ascause)
asError(maybeError: unknown): Error
Utility function that ensures a value is an Error instance. If the value is already an Error, it's returned as-is. Otherwise, it's wrapped in a new Error with the original value as cause.
try {
    // something that might throw
} catch (e) {
    const error = asError(e); // guaranteed to be an Error instance
    console.error(error);
}License
Less formally: Do what you want. The index.ts is short and dependency free: copy/paste/change.