Skip to main content
Asynchronous programming allows your code to handle time-consuming operations without blocking execution. TypeScript adds type safety to async operations.

Promises

Promises represent values that will be available in the future:
const myPromise = new Promise<number>((resolve, reject) => {
    setTimeout(() => {
        // resolve(100);
        reject('Mi amigo se perdio');
    }, 2000); // 2 seconds
});
Promise<number> indicates this promise will resolve to a number value. TypeScript uses this for type checking in .then() callbacks.

Handling Promises

Use .then(), .catch(), and .finally() to handle promise results:
myPromise
    .then((money) => {
        console.log(`My money is back ${money}`);
    })
    .catch((reason) => {
        console.warn(reason);
    })
    .finally(() => {
        console.log('Pues a seguir con mi vida');
    });
  • .then(): Runs when the promise resolves successfully
  • .catch(): Runs when the promise rejects (error handling)
  • .finally(): Always runs, regardless of success or failure

Fetch API with Promises

The Fetch API returns promises for HTTP requests:
import type { Welcome } from "../data/giphy.response";

const API_KEY = 'XXys76UFC1WXb3lwBtQP4oZi5HQskz61';

const myRequest = fetch(
    `https://api.giphy.com/v1/gifs/random?api_key=${API_KEY}`
);

myRequest
    .then((response) => response.json())
    .then(({ data }: Welcome) => {
        const imageUrl = data.images.original.url;
        createImageInsideDOM(imageUrl);
    })
    .catch((error) => {
        console.error(error);
    });
Chaining .then() calls allows you to process data in steps: first convert to JSON, then extract the data you need.

Async/Await Syntax

Async/await provides a cleaner syntax for working with promises:
const getRandomGifUrL = async () => {
    const response = await fetch(
        `https://api.giphy.com/v1/gifs/random?api_key=${API_KEY}`
    );

    const { data }: Welcome = await response.json();

    return data.images.original.url;
};

Using Async Functions

Async functions return promises, so you can use .then() or await:
// Using .then()
getRandomGifUrL().then(
    url => createImageInsideDOM(url)
);

// Or using await
const url = await getRandomGifUrL();
createImageInsideDOM(url);
You can only use await inside functions marked with async. Using await at the top level requires TypeScript’s esModuleInterop setting.

Type Safety with Async Operations

Define interfaces for API responses:
interface Welcome {
    data: {
        images: {
            original: {
                url: string;
            };
        };
    };
}

const { data }: Welcome = await response.json();
This provides:
  • Autocomplete for data.images.original.url
  • Compile-time errors if you access wrong properties
  • Self-documenting code

Error Handling with Async/Await

Use try/catch blocks:
const getRandomGifUrL = async () => {
    try {
        const response = await fetch(
            `https://api.giphy.com/v1/gifs/random?api_key=${API_KEY}`
        );

        if (!response.ok) {
            throw new Error(`HTTP error! status: ${response.status}`);
        }

        const { data }: Welcome = await response.json();
        return data.images.original.url;
    } catch (error) {
        console.error('Failed to fetch GIF:', error);
        throw error; // Re-throw if needed
    }
};

Promises vs Async/Await

Compare the two approaches:

With Promises

fetch(url)
    .then(response => response.json())
    .then(data => processData(data))
    .catch(error => console.error(error));

With Async/Await

try {
    const response = await fetch(url);
    const data = await response.json();
    processData(data);
} catch (error) {
    console.error(error);
}
Async/await is generally easier to read and maintain, especially for complex async logic with multiple steps.

Common Patterns

Parallel Requests

Run multiple async operations simultaneously:
const [users, posts, comments] = await Promise.all([
    fetch('/api/users').then(r => r.json()),
    fetch('/api/posts').then(r => r.json()),
    fetch('/api/comments').then(r => r.json()),
]);

Sequential Operations

Run operations one after another:
const user = await fetchUser();
const posts = await fetchUserPosts(user.id);
const details = await fetchPostDetails(posts[0].id);

Helper Functions

Create reusable async utilities:
const createImageInsideDOM = (url: string) => {
    const img = document.createElement('img');
    img.src = url;
    document.body.append(img);
};

getRandomGifUrL().then(url => createImageInsideDOM(url));

Best Practices

  • Always handle errors: Use .catch() or try/catch
  • Type your promises: Use Promise<T> generic types
  • Prefer async/await: It’s more readable than promise chains
  • Use Promise.all(): For parallel operations
  • Check response status: Fetch doesn’t reject on HTTP errors

Build docs developers (and LLMs) love