Handling Async/Await Pitfalls in TypeScript for Robust API Calls
Learn common async/await mistakes in TypeScript and how to handle them for reliable API calls.
Async/await is a powerful feature in TypeScript that makes asynchronous code easier to write and read. However, beginners often run into common pitfalls when handling API calls, leading to bugs or unhandled errors. This article will walk you through these pitfalls with practical examples and show you how to avoid them for more robust code.
The first common mistake is not handling errors properly. When calling an API asynchronously, things like network failures or invalid responses can happen. If you don't catch these errors, your app can crash or behave unpredictably.
async function fetchUser() {
const response = await fetch('https://api.example.com/user');
const data = await response.json();
return data;
}
// Using the function
fetchUser().then(user => console.log(user));In the example above, if the fetch fails or the response isn’t JSON, the app will throw an error. To fix this, wrap the await calls in a try-catch block to catch and handle errors gracefully.
async function fetchUserSafe() {
try {
const response = await fetch('https://api.example.com/user');
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
const data = await response.json();
return data;
} catch (error) {
console.error('Failed to fetch user:', error);
// Handle error: return default data or rethrow
return null;
}
}Another pitfall is forgetting to await a promise. If you omit the await keyword, your code might continue executing before the asynchronous operation completes, causing data inconsistencies or runtime errors.
async function fetchUserWrong() {
const userPromise = fetch('https://api.example.com/user');
// Missing await here
const data = await userPromise.json(); // This will cause an error because userPromise is a Response, not a Promise<Response>
return data;
}The correct approach is to await the fetch call before trying to use the response object.
async function fetchUserCorrect() {
const response = await fetch('https://api.example.com/user');
const data = await response.json();
return data;
}Finally, handling multiple async calls often causes confusion. If you have independent API calls, use Promise.all to run them concurrently and handle their results together.
async function fetchMultipleUsers() {
try {
const urls = ['https://api.example.com/user/1', 'https://api.example.com/user/2'];
const responses = await Promise.all(urls.map(url => fetch(url)));
const data = await Promise.all(responses.map(res => {
if (!res.ok) {
throw new Error(`HTTP error! status: ${res.status}`);
}
return res.json();
}));
return data;
} catch (error) {
console.error('Error fetching multiple users:', error);
return [];
}
}By correctly handling errors, always awaiting promises, and using Promise.all for concurrent operations, you can make your TypeScript API calls more reliable and easier to maintain.