Published at July 1, 2025

Utility function that helps you handle promises

Introduction

tryCatch is a utility function that helps you handle promises in a more elegant way. It returns the result in the same scope and uses try-catch blocks to handle promise rejections.

Thumbnail for Utility function that helps you handle promises

Problem

There is no clean way to handle promises in JavaScript. Of course you can use try-catch blocks, but the problem with them is that when you want to use the Fulfilled data outside the try-catch block, you have to use let outside the statement, then assign it the value, and in my opinion this makes the code ugly.

tryCatch Function

So let's start with the code of this function:

type Fulfilled<T> = {
  data: T;
  error: null;
};

type Rejected<V> = {
  data: null;
  error: V;
};

type Return<T, V = Error> = Fulfilled<T> | Rejected<V>;

export async function tryCatch<T, V = Error>(
  promise: Promise<T>
): Promise<Return<T, V>> {
  try {
    const data = await promise;
    return { data, error: null };
  } catch (error) {
    return { data: null, error: error as V };
  }
}

As you can see this function is very simple, it takes a promise as an argument and returns a promise that resolves to an object with two properties: data and error. If the promise resolves successfully, data will contain the resolved value and error will be null. If the promise rejects, data will be null and error will contain the rejection reason.

What's beneficial about this function is that it allows you to handle promises in a more elegant way. Instead of using try-catch blocks, you can use this function to handle promises and get the result in a single object on the same level. This makes the code cleaner and easier to read.

You can just check if any error occurs by checking the error property of the returned object, just like that:

const getUser = async () => {
  // simulate chance for random error
  if (Math.random() > 0.5) {
    return { name: "Acne" };
  } else {
    throw new Error("Connection timeout.");
  }
};

// using try-catch blocks

let userName;

try {
  const user = await getUser();
  userName = user.name;
} catch (error) {
  console.error("There was an error", error);
}

console.log(`Hello ${userName}`);

// using tryCatch function

const { data, error } = await tryCatch(getUser());

if (error) {
  console.error("There was an error", error);
  return;
}

console.log(`Hello ${data.name}`);