Blog / Typescript

How to use Promises and async/await in TypeScript

Promises and async/await in TypeScript

In this post find out about promises and async/await in TypeScript

Will MaygerWill Mayger
May 28, 2023
Article

Asynchronous programming is a crucial aspect of modern web development, and TypeScript provides powerful features to handle asynchronous operations effectively. Promises and async/await are two key features that simplify working with asynchronous code and make it more readable and maintainable. In this article, we’ll explore how to use Promises and async/await in TypeScript to handle asynchronous operations seamlessly.

Understanding Promises

Promises are a built-in feature in JavaScript that provide a clean and structured way to work with asynchronous operations. A Promise represents a value that may be available in the future, either as a successful result or as an error.

In TypeScript, Promises have a generic type that represents the type of the resolved value. The Promise constructor takes a single argument: a callback function that receives two parameters, resolve and reject. The resolve function is called when the asynchronous operation succeeds, and the reject function is called when it fails.

const promise = new Promise<number>((resolve, reject) => {
  // Asynchronous operation
  if (/* operation is successful */) {
    resolve(42); // Resolving with a value
  } else {
    reject(new Error("Operation failed")); // Rejecting with an error
  }
});

In this example, we create a Promise that resolves with the value 42 if the asynchronous operation succeeds. If it fails, we reject the Promise with an error.

To handle the result of a Promise, you can use the then method. The then method takes two optional callback functions: the onFulfilled callback for handling the resolved value and the onRejected callback for handling errors.

promise.then(
  (result) => {
    console.log(`The result is: ${result}`);
  },
  (error) => {
    console.error(`An error occurred: ${error.message}`);
  }
);

In this example, we use the then method to handle the resolved value and the rejected error of the Promise. The onFulfilled callback logs the result, while the onRejected callback logs the error message.

Promises provide a straightforward way to handle asynchronous operations and enable chaining of multiple asynchronous actions using the then method.

Introducing async/await

async/await is a syntactic sugar built on top of Promises that provides a more intuitive way to write asynchronous code. It allows you to write asynchronous code that looks similar to synchronous code, making it easier to understand and maintain.

The async keyword is used to define a function that contains asynchronous operations. Inside an async function, you can use the await keyword to pause the execution and wait for a Promise to resolve.

async function fetchData() {
  try {
    const result = await fetch(url); // Pause execution until the Promise is resolved
    const data = await result.json(); // Pause execution until the Promise is resolved
    // Process the data
  } catch (error) {
    // Handle errors
  }
}

In this example, the fetchData function is defined as an async function. Inside the function, we use the await keyword to wait for the fetch Promise to resolve. Once resolved, we use await again to wait for the json Promise to resolve. This allows us to write asynchronous code in a more synchronous style.

The await keyword can only be used within an async function, and it can only be used with Promises. If the value after await is not a Promise, it is automatically wrapped in a resolved Promise.

async/await makes it easier to handle asynchronous

code with a more linear and readable flow, reducing the need for nested callbacks or complex Promise chaining.

Error Handling with async/await

When working with async/await, error handling becomes straightforward and natural. You can use a try...catch block to catch and handle errors that occur within an async function.

async function fetchData() {
  try {
    const result = await fetch(url);
    const data = await result.json();
    // Process the data
  } catch (error) {
    console.error(`An error occurred: ${error.message}`);
  }
}

In this example, the try block contains the asynchronous code, and the catch block handles any errors that occur during the execution. If an error is thrown within the try block or any of the awaited Promises reject, the execution flow jumps to the catch block.

Promise.all and Promise.race

Promises provide two useful methods, Promise.all and Promise.race, to handle multiple Promises concurrently.

Promise.all takes an array of Promises and returns a new Promise that resolves when all the input Promises have resolved. The resolved values of the input Promises are collected into an array in the same order.

const promise1 = fetchDataFromSource1();
const promise2 = fetchDataFromSource2();

Promise.all([promise1, promise2])
  .then(([result1, result2]) => {
    // Process the results
  })
  .catch((error) => {
    // Handle errors
  });

In this example, we use Promise.all to wait for both promise1 and promise2 to resolve. Once resolved, we access the results in the then block.

Promise.race takes an array of Promises and returns a new Promise that resolves or rejects as soon as any of the input Promises resolves or rejects. The resolved or rejected value of the first resolved or rejected Promise is used.

const promise1 = fetchDataFromSource1();
const promise2 = fetchDataFromSource2();

Promise.race([promise1, promise2])
  .then((result) => {
    // Process the result
  })
  .catch((error) => {
    // Handle errors
  });

In this example, we use Promise.race to determine which Promise resolves or rejects first. The result or error of the fastest Promise is used in the then or catch block.

Conclusion

Promises and async/await are powerful features in TypeScript that simplify asynchronous programming and make it more readable and maintainable. Promises provide a structured way to handle asynchronous operations, allowing you to work with asynchronous code in a more predictable manner. async/await builds upon Promises and allows you to write asynchronous code in a synchronous style, making it easier to understand and reason about.

By mastering Promises and async/await, you can handle asynchronous operations more effectively, write cleaner and more maintainable code, and build robust and responsive applications.

There we have promises and async/await in TypeScript, if you want more like this be sure to check out some of my other posts!

Foxi - Budget Planner & Tracker

Foxi

Budget Planner & Tracker

More money in your pocket by the end of the month.

Free to use and no account needed.

Get started now.

Get the app

Some graphics used on this post were made using icons from flaticon.

Latest Posts

Learn React, JavaScript and TypeScript

Learn React, JavaScript and TypeScript

Join the platform that top tier companies are using.
Master the skills you need to succeed as a software engineer and take your career to the next level with Pluralsight.

Start here

Become an expert in ReactJS, TypeScript, and JavaScript.

Here you will find my personal recomendations to you, for full disclosure I earn a small commission from some of these links, but I only recommend what I trust and personally use.

Good things are coming, don't miss out!

Good things are coming, don't miss out!

Follow me on Twitter to stay up to date and learn frontend, React, JavaScript, and TypeScript tips and tricks!

Are you a novice, intermediate or expert react engineer?

Find out here by taking my fun, interactive, quick quiz which takes approximately 1 - 3 minutes. How well will you will do?

Foxi - Budget Planner & Tracker

Foxi

Budget Planner & Tracker

More money in your pocket by the end of the month.

Free to use and no account needed.

Get started now.

Get the app