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