Understanding TypeScript Promises

Understanding TypeScript Promises

Introduction

TypeScript, being a superset of JavaScript, includes the same promise mechanism as JavaScript. In TypeScript, promises are used in much the same way, with the added benefit of strong typing.

You can read about JavaScript promises here.

This feature enhances code quality and maintainability by allowing you to specify the type of value that a promise will resolve with or the type of error it might reject with.

Here’s a basic overview of how you would use promises in TypeScript:

Defining a Promise

In TypeScript, you can define a promise with a specific type for the resolved value. Here’s an example:

let myPromise: Promise<string> = new Promise((resolve, reject) => {
    const condition = true;
    if (condition) {
        resolve("Promise resolved successfully.");
    } else {
        reject("Promise rejected.");
    }
});

myPromise
    .then((successMsg: string) => console.log(successMsg))
    .catch((errorMsg: string) => console.log(errorMsg));

In this example, Promise<string> indicates that the promise, when resolved, will provide a string value.

This constructor takes a function, called the executor, that contains the asynchronous operation. The executor function has two parameters, resolve and reject, which are functions themselves. resolve is called when the operation completes successfully, and reject is called if an error occurs.

Using Promises with Functions

Consider a function that returns a promise. You can specify the return type of the promise:

function fetchData(url: string): Promise<any> {
    return fetch(url)
        .then(response => response.json())
        .catch(error => console.error("Error:", error));
}

fetchData('https://jsonplaceholder.typicode.com/posts/1')
    .then(data => console.log(data));

Here, fetchData returns a promise that resolves with any type (Promise<any>). In real-world scenarios, you would replace any with a more specific type that matches the expected data structure.

Async/Await with Promises

TypeScript also supports the async/await syntax, which works with promises and can make asynchronous code look and behave a bit more like synchronous code:

async function fetchAndProcessData(url: string): Promise<void> {
    try {
        const data = await fetchData(url);
        console.log(data);
        // Additional processing...
    } catch (error) {
        console.error("Error:", error);
    }
}

fetchAndProcessData('https://jsonplaceholder.typicode.com/posts/1');

In this example, async marks the function as asynchronous, and await is used to wait for the promise returned by fetchData to resolve.

TypeScript and Promise Chaining

You can use TypeScript’s type checking with promise chaining as well:

function processString(str: string): Promise<number> {
    return new Promise<number>((resolve, reject) => {
        resolve(str.length);
    });
}

myPromise
    .then(processString)
    .then((length: number) => console.log(`String length: ${length}`))
    .catch((error: string) => console.error(error));

Here, processString is a function that takes a string and returns a promise that resolves with a number. TypeScript checks the types throughout the chain.

Conclusion

Promises in TypeScript offer the same functionality as in JavaScript but with the added advantage of type safety.

This feature of TypeScript helps in writing more robust and less error-prone code, especially when dealing with complex asynchronous operations.

By leveraging TypeScript’s type system with promises, you can improve the clarity and predictability of your asynchronous code.

Stephen

Hi, my name is Stephen Finchett. I have been a software engineer for over 30 years and worked on complex, business critical, multi-user systems for all of my career. For the last 15 years, I have been concentrating on web based solutions using the Microsoft Stack including ASP.Net, C#, TypeScript, SQL Server and running everything at scale within Kubernetes.