Async/Await & Promises
Type asynchronous code correctly with Promise generics, error unions, and concurrent operation typing.
Typing Promises
Promise<T> describes the resolved value type. Async functions implicitly return Promise<T> based on return expressions. Annotate async function return types on exported APIs for stable contracts.
Avoid `Promise<any>` — specify the resolved shape or use `unknown` and narrow after await. Generic Promise utilities preserve types through chains.
- `Promise<T>` for resolved type
- Annotate exported async returns
- Never `Promise<any>` on public APIs
async function fetchUser(id: string): Promise<User | null> {
const res = await fetch(`/api/users/${id}`);
if (!res.ok) return null;
return res.json();
}Error Handling Types
Model errors as discriminated unions or custom Error subclasses with typed properties. Libraries like neverthrow and ts-results provide Result types that make failure explicit in signatures.
Throwing remains idiomatic in many Node frameworks — type catch blocks with `unknown` and narrow with `instanceof` rather than assuming Error shape.
- Result types for explicit errors
- Catch `unknown`, narrow safely
- Custom Error classes with typed fields
type Result<T> = { ok: true; value: T } | { ok: false; error: AppError };Typing Promise Combinators
`Promise.all` on a tuple preserves tuple types in TypeScript — each resolved type maps to the corresponding input. `Promise.all` on a homogeneous array returns `T[]`. `Promise.allSettled` returns status objects typed per input.
Use `Awaited<ReturnType<typeof fn>>` to extract resolved types from async functions in utility types without duplicating definitions.
- Tuple preservation in Promise.all
- Awaited for resolved type extraction
- allSettled for partial failure typing
const [user, posts] = await Promise.all([ fetchUser(id), fetchPosts(id), ] as const);
Async Iteration Types
Async generators return `AsyncGenerator<T>`. `for await...of` works on `AsyncIterable<T>`. Type streaming parsers and paginated fetchers with these interfaces for clarity.
Node.js streams implement async iteration in modern typings — cast carefully or use wrapper utilities when stream types and async iterator types diverge across @types versions.
- AsyncGenerator for streaming
- AsyncIterable interface
- Type paginated fetch pipelines
Framework Integration
Next.js Server Components and Route Handlers use async functions — return types must be serializable. React Server Actions type FormData inputs and return values explicitly for end-to-end safety.
Express and Fastify handlers benefit from typed request/response generics. Align async error middleware with your Result vs throw convention so types and runtime behavior match.
- Server Components need serializable returns
- Type Server Action inputs/outputs
- Align throw vs Result with middleware