TypeScript Async and Await

Async and await are keywords that make asynchronous code look and behave like synchronous code. Asynchronous operations — reading files, calling APIs, querying databases — take time. Instead of blocking the entire program while waiting, async code lets other work continue. The async and await keywords, combined with TypeScript's type system, make this code readable, type-safe, and easy to debug.

Synchronous vs Asynchronous

SYNCHRONOUS — each step waits for the one before:
  Step 1: Make tea       → waits 5 minutes (nothing else happens)
  Step 2: Read news      → starts only after tea is ready
  Step 3: Eat breakfast  → starts only after reading

ASYNCHRONOUS — tasks overlap:
  Step 1: Start boiling water   → don't wait
  Step 2: Read news             → while water boils
  Step 3: Water ready → make tea → continue breakfast
  Total time: much less than waiting sequentially

The async Keyword

Adding async before a function declaration makes that function return a Promise automatically. The return type becomes Promise<ReturnType>.

// Regular function
function getName(): string {
    return "Priya";
}

// Async function — same logic, wrapped in a Promise
async function getNameAsync(): Promise<string> {
    return "Priya";   // TypeScript wraps this in Promise<string> automatically
}

// Calling the async function
getNameAsync().then(name => console.log(name));  // Priya

The await Keyword

await pauses the function until the Promise resolves and returns the resolved value. It can only be used inside an async function.

FLOW:

async function doWork() {
    console.log("Starting...");
    let result = await someAsyncTask();   // pause here until done
    console.log("Got result:", result);   // resumes here after task completes
    console.log("Done.");
}

Typing Async Functions

interface User {
    id: number;
    name: string;
    email: string;
}

// Return type is always Promise<T> for async functions
async function fetchUser(id: number): Promise<User> {
    // Simulating a real API call with a timer
    await delay(1000);   // wait 1 second
    return {
        id,
        name: "Vikram",
        email: "vikram@mail.com"
    };
}

function delay(ms: number): Promise<void> {
    return new Promise(resolve => setTimeout(resolve, ms));
}

async function main(): Promise<void> {
    let user = await fetchUser(1);
    console.log(user.name);   // Vikram (after 1 second)
    console.log(user.email);  // vikram@mail.com
}

main();

Error Handling with Async/Await

Wrap async code in try/catch to handle errors from awaited Promises. This works exactly like synchronous error handling.

async function loadProduct(id: number): Promise<void> {
    try {
        let response = await fetch(`https://api.example.com/products/${id}`);

        if (!response.ok) {
            throw new Error(`Server returned ${response.status}`);
        }

        let product: { name: string; price: number } = await response.json();
        console.log(`Product: ${product.name}, Price: ₹${product.price}`);
    } catch (error: unknown) {
        if (error instanceof Error) {
            console.log(`Failed to load product: ${error.message}`);
        }
    }
}

Multiple Awaits in Sequence

SEQUENCE:
  Step 1 finishes → Step 2 starts → Step 3 starts
  Total time = time(1) + time(2) + time(3)

async function processOrder(orderId: number): Promise<void> {
    console.log("Starting order processing...");

    let order   = await getOrder(orderId);     // wait for order
    let user    = await getUser(order.userId); // wait for user
    let payment = await chargeCard(order.total); // wait for payment

    console.log(`Order ${orderId} for ${user.name}: ${payment}`);
}

Parallel Execution with Promise.all

When tasks do not depend on each other, run them at the same time using Promise.all. This reduces total waiting time significantly.

PARALLEL:
  Task 1 ─────────────────── done
  Task 2 ──────── done
  Task 3 ───────────────────────── done
  Total time = time of the SLOWEST task

async function loadDashboardData(): Promise<void> {
    try {
        // Start all three requests at the same time
        let [user, orders, notifications] = await Promise.all([
            fetchUser(1),
            fetchOrders(1),
            fetchNotifications(1)
        ]);

        console.log(`Welcome ${user.name}`);
        console.log(`Orders: ${orders.length}`);
        console.log(`Notifications: ${notifications.length}`);
    } catch (error) {
        console.log("One or more requests failed");
    }
}

Promise.allSettled — Run All, Get All Results

// allSettled waits for all promises, even if some fail
async function tryMultipleSources(): Promise<void> {
    let results = await Promise.allSettled([
        fetchUser(1),
        fetchUser(999),    // this might fail (user not found)
        fetchUser(2)
    ]);

    for (let result of results) {
        if (result.status === "fulfilled") {
            console.log("Success:", result.value.name);
        } else {
            console.log("Failed:", result.reason);
        }
    }
}

Async with Interfaces and Generics

interface ApiResponse<T> {
    data: T;
    status: number;
    message: string;
}

async function apiGet<T>(url: string): Promise<ApiResponse<T>> {
    let response = await fetch(url);

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

    let data: T = await response.json();
    return {
        data,
        status: response.status,
        message: "OK"
    };
}

interface Product {
    id: number;
    name: string;
    price: number;
}

async function getProduct(): Promise<void> {
    let result = await apiGet<Product>("https://api.example.com/products/1");
    console.log(result.data.name);   // TypeScript knows this is a Product
    console.log(result.status);      // 200
}

Async/Await Summary

ConceptSyntaxPurpose
Async functionasync function f(): Promise<T>Marks a function as asynchronous
Awaitlet x = await promiseWaits for a promise and gets its value
Error handlingtry / catchCatches errors from awaited promises
Sequential callsMultiple await statementsRun tasks one after another
Parallel callsawait Promise.all([...])Run tasks simultaneously
All resultsawait Promise.allSettled([...])Get all results even if some fail

Leave a Comment

Your email address will not be published. Required fields are marked *