Skip to content

Instantly share code, notes, and snippets.

@nash403
Forked from t3dotgg/try-catch.ts
Last active March 26, 2025 21:27
Show Gist options
  • Save nash403/a248697941b5b5be970d9658f32197ff to your computer and use it in GitHub Desktop.
Save nash403/a248697941b5b5be970d9658f32197ff to your computer and use it in GitHub Desktop.
My 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>;
type MaybePromise<T, Args extends any[]> = ((...args: Args) => T) | Promise<T>;
// Main wrapper function
async function tryCatch<T, Args extends any[], E = Error>(
input: MaybePromise<T, Args>,
...args: Args
): Promise<Result<T, E>> {
try {
// Check if input is a function (sync case) and call it with arguments, otherwise assume it's a Promise
const data = await Promise.resolve(
typeof input === "function" ? input(...args) : input
);
return { data, error: null };
} catch (error) {
return { data: null, error: error as E };
}
}
// see TS this playground https://www.typescriptlang.org/play/?ssl=14&ssc=13&pln=2&pc=13#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
async function doMathAsync() {
const value = Math.random()
if (value > 0.5) throw new Error('too large')
return Promise.resolve(value)
}
function doMath(a: number = 0) {
const value = Math.random() + a
if (value < 0.5) throw new Error('too large')
return value
}
async function fetchData(id: number): Promise<string> {
if (id === 0) throw new Error("Invalid ID");
return `Data for ID ${id}`;
}
(async () => {
const { data, error } = await tryCatch(doMathAsync)
console.log('ex rand async fn:', data, error)
})();
(async () => {
const { data, error } = await tryCatch(() => doMath())
console.log('ex rand sync fn:', data, error)
})();
(async () => {
const { data, error } = await tryCatch(doMath)
console.log('ex rand sync fn ref:', data, error)
})();
(async () => {
const { data, error } = await tryCatch(doMath, 2)
console.log('ex rand sync fn ref with args:', data, error)
})();
(async () => {
const { data, error } = await tryCatch(fetchData, 33)
console.log('ex async fn with args:', data, error)
})();
(async () => {
const { data, error } = await tryCatch(fetchData, 0)
console.log('ex async fn with args fail:', data, error)
})();
(async () => {
const { data, error } = await tryCatch(Promise.resolve("Some Data"))
console.log('ex promise resolve:', data, error)
})();
(async () => {
const { data, error } = await tryCatch(Promise.reject("Some Error"))
console.log('ex promise reject:', data, error)
})();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment