bugl
bugl
HomeLearnPatternsSearch
HomeLearnPatternsSearch

Loading lesson path

Learn/TypeScript/TypeScript Core
TypeScript•TypeScript Core

TypeScript Async Programming

Concept visual

TypeScript Async Programming

push / pop from the top({[← top

TypeScript enhances JavaScript's asynchronous capabilities with static typing, making your async code more predictable and maintainable.

Formula

This guide covers everything from basic async/await to advanced patterns.

This tutorial assumes basic knowledge of JavaScript Promises and asynchronous programming. If you're new to these concepts, check out our JavaScript Async tutorial first.

Promises in TypeScript

TypeScript enhances JavaScript Promises with type safety through generics. A

Formula

Promise < T >

represents an asynchronous operation that will complete with a value of type T or fail with a reason of type any.

Key Points:

Formula

Promise < T >
  • Generic type where T is the type of the resolved value

Formula

Promise < void >
- For Promises that don't return a value

Formula

Promise < never >
  • For Promises that never resolve (rare)

Basic Promise Example

Formula

// Create a typed Promise that resolves to a string const fetchGreeting = (): Promise < string > => {
return new Promise((resolve, reject) => {
setTimeout(() => {
const success = Math.random() > 0.5;
if (success) {
resolve("Hello, TypeScript!");
} else {
reject(new Error("Failed to fetch greeting"));
}
}, 1000);
});
};
// Using the Promise with proper type inference fetchGreeting().then((greeting) => {
// TypeScript knows 'greeting' is a string console.log(greeting.toUpperCase());
}).catch((error: Error) => {
console.error("Error:", error.message);
});

Promise States and Type Flow

Promise State Flow:

pending → fulfilled (with value: T) // Success case pending → rejected (with reason: any) // Error case TypeScript tracks these states through the type system, ensuring you handle both success and error cases properly.

The type parameter in

Formula

Promise < T >

tells TypeScript what type the Promise will resolve to, allowing for better type checking and IDE support.

Async/Await with TypeScript

TypeScript's async/await syntax provides a cleaner way to work with Promises, making asynchronous code look and behave more like synchronous code while maintaining type safety.

Key Benefits of Async/Await

Readability

: Sequential code that's easier to follow

Error Handling

Formula

: Use try/catch for both sync and async errors

Debugging

Formula

: Easier to debug with synchronous - like stack traces

Type Safety

: Full TypeScript type inference and checking

Basic Async/Await Example

// Define types for our API response interface User {
id: number;
name: string;
email: string;
role: 'admin' | 'user' | 'guest';
}

Formula

// Function that returns a Promise of User array async function fetchUsers(): Promise < User[]> {
console.log('Fetching users...');
// Simulate API call await new Promise(resolve => setTimeout(resolve, 1000));
return [
{ id: 1, name: 'Alice', email: 'alice@example.com', role: 'admin' },
{ id: 2, name: 'Bob', email: 'bob@example.com', role: 'user' }
];
}
// Async function to process users async function processUsers() {
try {
// TypeScript knows users is User[]
const users = await fetchUsers();
console.log(`Fetched ${users.length} users`);
// Type-safe property access const adminEmails = users.filter(user => user.role === 'admin').map(user => user.email);
console.log('Admin emails:', adminEmails);
return users;
} catch (error) {
if (error instanceof Error) {
console.error('Failed to process users:', error.message);
} else {
console.error('An unknown error occurred');
}
throw error; // Re-throw to let caller handle
}
}
// Execute the async function processUsers().then(users => console.log('Processing complete')).catch(err => console.error('Processing failed:', err));

Async Function Return Types

All async functions in TypeScript return a Promise.

The return type is automatically wrapped in a Promise:

async function getString(): string { }        // Error: must return Promise async function getString(): Promise<string> { } // Correct

Parallel Execution with Promise.all Run multiple async operations in parallel and wait for all to complete:

interface Product {
id: number;
name: string;
price: number;
}
async function fetchProduct(id: number): Promise<Product> {
console.log(`Fetching product ${id}...`);
await new Promise(resolve => setTimeout(resolve, Math.random() * 1000));
return { id, name: `Product ${id}`, price: Math.floor(Math.random() * 100) };
}
async function fetchMultipleProducts() {
try {
// Start all fetches in parallel const [product1, product2, product3] = await Promise.all([
fetchProduct(1), fetchProduct(2), fetchProduct(3)
]);
const total = [product1, product2, product3].reduce((sum, product) => sum + product.price, 0);
console.log(`Total price: $${total.toFixed(2)}`);
} catch (error) {
console.error('Error fetching products:', error);
}
}
fetchMultipleProducts();

Note:

All async functions in TypeScript return a Promise.
The type parameter of the Promise corresponds to the return type you declare after the Promise keyword.

Typing Callbacks for Async Operations

Formula

For traditional callback - based asynchronous code, TypeScript helps ensure proper typing of the callback parameters:

Example

Formula

// Define a type for the callback type FetchCallback = (error: Error | null, data?: string) => void;

// Function that takes a typed callback function fetchDataWithCallback(url: string, callback: FetchCallback): void {

// Simulate async operation setTimeout(() => {
try {
// Simulate successful response callback(null, "Response data");
} catch (error) {
callback(error instanceof Error ? error : new Error('Unknown error'));
}
}, 1000);
}
// Using the callback function fetchDataWithCallback('https://api.example.com', (error, data) => {
if (error) {
console.error('Error:', error.message);
return;
}
// TypeScript knows data is a string (or undefined)
if (data) {
console.log(data.toUpperCase());
}
});

Promise Combinations

TypeScript provides powerful utility types and methods for working with multiple Promises.

Formula

These methods help you manage concurrent operations and handle their results in a type - safe way.

Promise Combination Methods

Promise.all() - Waits for all promises to resolve Promise.race() - Returns the first settled promise Promise.allSettled() - Waits for all to settle (success or failure) Promise.any() - Returns the first fulfilled promise

Formula

Promise.all - Parallel Execution

Run multiple promises in parallel and wait for all to complete. Fails fast if any promise rejects.

Formula

// Different types of promises const fetchUser = (id: number): Promise <{ id: number; name: string }> =>

Promise.resolve({ id, name: User ${id} });

const fetchPosts = (userId: number): Promise<Array<{ id: number; title: string }>> =>
Promise.resolve([
    { id: 1, title: 'Post 1' },
{ id: 2, title: 'Post 2' }
]);
const fetchStats = (userId: number): Promise<{ views: number; likes: number }> =>
Promise.resolve({ views: 100, likes: 25 });
// Run all in parallel async function loadUserDashboard(userId: number) {
try {
const [user, posts, stats] = await Promise.all([
fetchUser(userId), fetchPosts(userId), fetchStats(userId)
]);
// TypeScript knows the types of user, posts, and stats console.log(`User: ${user.name}`);
console.log(`Posts: ${posts.length}`);
console.log(`Likes: ${stats.likes}`);
return { user, posts, stats };
} catch (error) {
console.error('Failed to load dashboard:', error);
throw error;
}
}

// Execute with a user ID

loadUserDashboard(1);

Formula

Promise.race - First to Settle

Useful for timeouts or getting the first successful response from multiple sources.

Formula

// Helper function for timeout const timeout = (ms: number): Promise < never > =>
new Promise((_, reject) =>
setTimeout(() => reject(new Error(`Timeout after ${ms}ms`)), ms)
);

Formula

// Simulate API call with timeout async function fetchWithTimeout < T > (
promise: Promise < T >, timeoutMs: number = 5000
): Promise<T> {
return Promise.race([
promise, timeout(timeoutMs).then(() => {
throw new Error(`Request timed out after ${timeoutMs}ms`);
}),
]);
}
// Usage example async function fetchUserData() {
try {
const response = await fetchWithTimeout(

Formula

fetch('https://api.example.com/user/1'),

3000 // 3 second timeout

);
const data = await response.json();
return data;
} catch (error) {
console.error('Error:', (error as Error).message);
throw error;
}
}

Formula

Promise.allSettled - Handle All Results
When you want to wait for all promises to complete, regardless of success or failure.
// Simulate multiple API calls with different outcomes const fetchData = async (id: number) => {
// Randomly fail some requests if (Math.random() > 0.7) {
throw new Error(`Failed to fetch data for ID ${id}`);
}
return { id, data: `Data for ${id}` };
};
// Process multiple items with individual error handling async function processBatch(ids: number[]) {
const promises = ids.map(id =>
fetchData(id).then(value => ({ status: 'fulfilled' as const, value })).catch(reason => ({ status: 'rejected' as const, reason }))
);
// Wait for all to complete const results = await Promise.allSettled(promises);
// Process results const successful = results.filter((result): result is PromiseFulfilledResult<{ status: 'fulfilled', value: any }> =>
result.status === 'fulfilled' &&
result.value.status === 'fulfilled'
).map(r => r.value.value);
const failed = results.filter((result): result is PromiseRejectedResult |
PromiseFulfilledResult<{ status: 'rejected', reason: any }> => {
if (result.status === 'rejected') return true;
return result.value.status === 'rejected';
});
console.log(`Successfully processed: ${successful.length}`);
console.log(`Failed: ${failed.length}`);
return { successful, failed };
}
// Process a batch of IDs processBatch([1, 2, 3, 4, 5]);

Warning:

When using

Promise.all with an array of promises that have different types, TypeScript will infer the result type as an array of the union of all possible types. For more precise typing, you may need to use type assertions or define the expected structure.

Error Handling in Async Code

Formula

TypeScript provides powerful tools for type - safe error handling in asynchronous code.

Let's explore different patterns and best practices.

Error Handling Strategies

Previous

TypeScript Declaration Merging

Next

TypeScript Decorators