Promise<T> — Typed Asynchronous Values
A `Promise<T>` is a typed placeholder for a value that will be available asynchronously. TypeScript's generic `Promise<T>` ensures that `.then()` callbacks receive the correct type, and callers know what to expect when the promise resolves. Understanding `Promise<T>` precisely is the foundation of all async TypeScript.
12 min•By Priygop Team•Updated 2026
Promise<T> — Types, Resolution & Chaining
Promise<T> — Types, Resolution & Chaining
// ── Promise<T> — explicitly typed ────────────────────────────
const taskPromise: Promise<Task> = new Promise((resolve, reject) => {
setTimeout(() => {
resolve({ id: 1, title: "Launch", status: "todo", /* ... */ } as Task);
}, 1000);
});
// ── .then() and .catch() are typed ────────────────────────────
taskPromise
.then((task: Task) => { // task is Task — TS infers this
console.log(task.title);
return task.id; // returns Promise<number>
})
.then((id: number) => { // chained — id is number
console.log("ID:", id);
})
.catch((error: unknown) => { // always use unknown for catch
if (error instanceof Error) {
console.error(error.message);
}
});
// ── Promise.resolve & Promise.reject ─────────────────────────
const resolved: Promise<string> = Promise.resolve("Hello");
const rejected: Promise<never> = Promise.reject(new Error("Oops"));
// ── Return types — async functions ────────────────────────────
// Always returns Promise<T> — TypeScript enforces this:
function fetchTask(id: number): Promise<Task | null> {
return fetch(`/api/tasks/${id}`)
.then((res) => res.json() as Promise<Task>)
.catch(() => null);
}
// ── void vs Promise<void> ─────────────────────────────────────
// void: synchronous, callers ignore return value
// Promise<void>: async side-effect, must be awaited
async function logAndSave(task: Task): Promise<void> {
await saveTask(task); // no meaningful return value, but async
}
// ── Awaited<T> — unwrap Promise types ─────────────────────────
type T1 = Awaited<Promise<string>>; // string
type T2 = Awaited<Promise<Promise<number>>>; // number (recursive)
type T3 = Awaited<ReturnType<typeof fetchTask>>; // Task | null
// ✅ Use Awaited when you need the resolved type of an async function:
type TaskResult = Awaited<ReturnType<typeof fetchTask>>; // Task | nullDiagram
Loading diagram…
A Promise settles ONCE — pending → fulfilled OR rejected
Common Mistakes
- Typing catch parameter as `Error` — pre-TypeScript 4, `catch(e)` implicitly typed `e` as `any`. With `strict`, the catch parameter is `unknown`. Always use `unknown` and narrow: `if (error instanceof Error)`.
- Returning `Promise<any>` — avoid this. If you don't know the return type, use `Promise<unknown>` and validate. `any` propagates through all callers.
- Not handling rejected promises — every `Promise` chain needs a `.catch()` or try/catch in an async function. Unhandled rejections crash Node.js (and trigger warnings in browsers).
Key Takeaways
- A `Promise<T>` is a typed placeholder for a value that will be available asynchronously.
- Typing catch parameter as `Error` — pre-TypeScript 4, `catch(e)` implicitly typed `e` as `any`. With `strict`, the catch parameter is `unknown`. Always use `unknown` and narrow: `if (error instanceof Error)`.
- Returning `Promise<any>` — avoid this. If you don't know the return type, use `Promise<unknown>` and validate. `any` propagates through all callers.
- Not handling rejected promises — every `Promise` chain needs a `.catch()` or try/catch in an async function. Unhandled rejections crash Node.js (and trigger warnings in browsers).