Async/Await

La programmazione asincrona rappresenta un paradigma fondamentale nello sviluppo moderno, permettendo l’esecuzione non-bloccante di operazioni che richiedono tempo. TypeScript potenzia questo paradigma fornendo tipizzazione statica completa per operazioni asincrone, garantendo type safety anche in contesti dove il valore di ritorno è disponibile solo in futuro.
Concetti Fondamentali
Il pattern async/await in TypeScript si basa sul tipo Promise<T> che rappresenta un valore che sarà disponibile in futuro. Una funzione marcata come async restituisce automaticamente una Promise, anche se il valore di ritorno è sincrono. La keyword await converte codice asincrono in una sintassi che appare sincrona.
async function fetchUserName(id: number): Promise<string> {
const response = await fetch(`/api/users/${id}`);
const user = await response.json();
return user.name; // TypeScript inferisce Promise<string>
}
Tipizzazione delle Promise
TypeScript fornisce controllo di tipo completo per le Promise, specificando il tipo del valore risolto e prevenendo errori comuni.
interface ApiResult<T> {
success: boolean;
data: T;
error?: string;
}
async function processApiResponse(): Promise<ApiResult<User[]>> {
const response = await fetch("/api/users");
const users: User[] = await response.json();
return { success: true, data: users };
}
Gestione degli Errori
TypeScript permette di tipizzare anche gli errori, migliorando la robustezza del codice e facilitando la gestione di diversi tipi di errori.
class ValidationError extends Error {
constructor(message: string, public field: string) {
super(message);
}
}
async function validateUser(data: UserInput): Promise<User> {
if (!data.email.includes("@")) {
throw new ValidationError("Invalid email", "email");
}
// ... resto della logica
}
Operazioni Parallele
TypeScript supporta operazioni asincrone parallele mantenendo la tipizzazione completa attraverso Promise.all, Promise.race e Promise.allSettled.
async function fetchUserProfile(userId: number): Promise<UserProfile> {
const [user, posts, followers] = await Promise.all([
fetchUser(userId), // Promise<User>
fetchUserPosts(userId), // Promise<Post[]>
fetchUserFollowers(userId), // Promise<User[]>
]);
return { user, posts, followers };
}
Async Iterators
TypeScript supporta async iterators e generators per processare stream di dati asincroni in modo elegante e type-safe.
async function* fetchUsersBatch(): AsyncGenerator<User[], void, unknown> {
let page = 1;
while (true) {
const users = await fetchUsersPage(page++);
if (users.length === 0) break;
yield users;
}
}
for await (const userBatch of fetchUsersBatch()) {
// userBatch è tipizzato come User[]
}
Utility Types per Async
TypeScript fornisce utility types specializzati per operazioni asincrone che facilitano la manipolazione di tipi Promise.
type Awaited<T> = T extends Promise<infer U> ? U : T;
type AsyncReturnType<T extends (...args: any) => Promise<any>> = T extends (
...args: any
) => Promise<infer R>
? R
: never;
// Trasforma tutti i metodi in async
type AsyncMethods<T> = {
[K in keyof T]: T[K] extends (...args: any[]) => any
? (...args: Parameters<T[K]>) => Promise<ReturnType<T[K]>>
: T[K];
};
Pattern Avanzati
La tipizzazione facilita l’implementazione di pattern robusti come retry, timeout, circuit breaker e fallback con type safety mantenuta.