Transitioning to TypeScript: The Ultimate Starter Guide - Part 5

TypeScript from JavaScript Part 5 of 7: Async/Await and Error Handling

Hello again, fellow developers! We have already covered a lot in our journey from JavaScript to TypeScript: basic and advanced types, modules, namespaces, decorators, and type guards. In this part, we will dive into one of the most powerful features of modern JavaScript and TypeScript: async/await and error handling.

As always, remember that the purpose of this series is not just to learn TypeScript, but to understand how it can simplify our work, save time, and elevate our apps. So, let's get started!

1. Understanding Promises

Before we dive into async/await, it's important to have a good understanding of Promises, as async/await is built on top of them.

A Promise in JavaScript (and therefore in TypeScript) is an object that represents the eventual completion or failure of an asynchronous operation. It is a way to handle asynchronous operations like HTTP requests, reading files, or timers, and allows us to write non-blocking code.

Here is how you create a Promise:

const promise = new Promise((resolve, reject) => {
  const success = true;

  if (success) {
    resolve('The operation was successful.');
  } else {
    reject('The operation failed.');
  }
});

promise.then((message) => {
  console.log('Success:', message);
}).catch((message) => {
  console.log('Failure:', message);
});

In this example, we create a Promise that either resolves or rejects based on the value of the success variable. If the operation is successful, we call the resolve function, otherwise, we call the reject function. We can then use the then method to handle the resolved value and the catch method to handle the rejected value.

2. Async/Await

Async/await is a modern way to work with Promises. It makes asynchronous code look and behave a little more like synchronous code, which makes it easier to read and understand.

a. Async Functions

An async function is a function declared with the async keyword. Async functions are instances of the AsyncFunction constructor, and the await keyword is permitted within them.

async function myFunction() {
  return 'Hello, World!';
}

myFunction().then((value) => {
  console.log(value); // Hello, World!
});

In this example, myFunction is an async function that returns a resolved Promise with the value 'Hello, World!'. We can then use the then method to handle the resolved value.

b. Await

The await keyword is used to pause and resume a JavaScript AsyncFunction and to wait for the Promise's resolution or rejection.

async function myFunction() {
  const promise = new Promise((resolve, reject) => {
    setTimeout(() => {
      resolve('Hello, World!');
    }, 2000);
  });

  const result = await promise;
  console.log(result);
}

myFunction();

In this example, myFunction is an async function that creates a Promise that resolves after 2 seconds. The await keyword is used to wait for the Promise to resolve before logging the result to the console.

3. Error Handling

Error handling is crucial for any application. In asynchronous code, errors can occur in two ways: synchronous errors (e.g., type errors, syntax errors) and asynchronous errors (e.g., network errors, timeout errors).

a. Try/Catch

The try/catch statement allows you to define a block of code to be tested for errors while it is being executed (try), and a block of code to be executed if an error occurs (catch).

async function myFunction() {
  try {
    const promise = new Promise((resolve, reject) => {
      setTimeout(() => {
        reject('Something went wrong.');
      }, 2000);
    });

    const result = await promise;
    console.log(result);
  } catch (error) {
    console.error(error);
  }
}

myFunction();

In this example, myFunction is an async function that creates a Promise that rejects after 2 seconds. The await keyword is used to wait for the Promise to resolve or reject. If the Promise resolves, the result is logged to the console. If the Promise rejects, the error is caught and logged to the console.

b. Error Propagation

In asynchronous code, it's important to propagate errors up the call stack so they can be handled properly.

async function myFunction() {
  const promise = new Promise((resolve, reject) => {
    setTimeout(() => {
      reject(new Error('Something went wrong.'));
    }, 2000);
  });

  const result = await promise;
  return result;
}

async function main() {
  try {
    const result = await myFunction();
    console.log(result);
  } catch (error) {
    console.error(error.message);
  }
}

main

();

In this example, myFunction is an async function that creates a Promise that rejects after 2 seconds. The main function is another async function that calls myFunction and handles any errors that occur.

Conclusion

In this part, we have learned about async/await and error handling in TypeScript. We have learned how to create async functions, how to use the await keyword to wait for Promises to resolve or reject, and how to handle errors using try/catch and error propagation.

Stay tuned for the next part of this series, where we will dive into advanced topics like generics and utility types!

Happy coding! 💻✨

Did you find this article valuable?

Support Innovate Sphere by becoming a sponsor. Any amount is appreciated!