Skip to content

Instantly share code, notes, and snippets.

@t3dotgg
Last active April 26, 2025 18:55
Show Gist options
  • Save t3dotgg/a486c4ae66d32bf17c09c73609dacc5b to your computer and use it in GitHub Desktop.
Save t3dotgg/a486c4ae66d32bf17c09c73609dacc5b to your computer and use it in GitHub Desktop.
Theo's preferred way of handling try/catch in TypeScript
// Types for the result object with discriminated union
type Success<T> = {
data: T;
error: null;
};
type Failure<E> = {
data: null;
error: E;
};
type Result<T, E = Error> = Success<T> | Failure<E>;
// Main wrapper function
export async function tryCatch<T, E = Error>(
promise: Promise<T>,
): Promise<Result<T, E>> {
try {
const data = await promise;
return { data, error: null };
} catch (error) {
return { data: null, error: error as E };
}
}
@Joseph-Martre
Copy link

@osoclos Let me explain my solution safe-throw:

An example function:

import * as st from 'safe-throw';

const fn = () => Math.random() < 0.5 ? 10 : st.err('Random');

The problem here is "how to create a safe wrapper with good DX for outside APIs that can throw". Theo's code is a solution to that. Your code is a way to control errors in your own hand-rolled APIs. These two problems are very much not the same.

@aquapi
Copy link

aquapi commented Apr 19, 2025

@Joseph-Martre it has an API for that

import * as native from 'safe-throw/native';

const safePromise = await native.tryPromise(promise); // T | native.Err
const safeFetch = native.asyncTry(fetch);

@thelinuxlich
Copy link

This thread nerdsniped me to unify the sync/async methods in my lib: https://github.com/thelinuxlich/go-go-try

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment