In TypeScript a promise has the type Promise<T>, where T is the type of the value it resolves with. A function that returns a promise declares it in its return type, and the value you get from then or await has type T.
The promise mechanics (states, the microtask queue, chaining) are plain JavaScript, covered in JavaScript promises. This page is about the types.
Typing new Promise and resolve
When new Promise is the return value of a function with a declared return type, T comes from that. On its own, TypeScript does not infer T from the resolve calls, and you get Promise<unknown>. Pass the type argument explicitly:
Two details. resolve is typed from T, so resolve("42") in a Promise<number> is a compile error. And resolve() with no argument is only allowed when T includes void: in a Promise<number> it is error TS2794 (Expected 1 arguments, but got 0. Did you forget to include 'void' in your type argument to 'Promise'?).
The reject side is not typed. There is no Promise<T, E>: a promise can reject with any value.
then, catch and finally
Each then returns a new promise typed by what its callback returns. If the callback returns a promise, TypeScript unwraps it, so you never get Promise<Promise<T>>.
The catch callback's parameter is typed any in the standard library, not unknown. Nothing stops you from writing e.message on a value that might be a string. Annotate it as unknown, as above, and narrow before use. try/catch around await does better: under strict, its catch variable is already unknown (see error handling).
Promise.all Returns a Tuple
Given an array literal of different promise types, Promise.all returns a promise of a tuple, with each position keeping its own type:
Non-promise values can be mixed in and pass through unchanged. Promise.all rejects as soon as one input rejects, and the other results are lost. Promise.race resolves or rejects with the first to settle and is typed as the union of the inputs; Promise.any resolves with the first success and rejects with an AggregateError only if every input fails.
Promise.allSettled and Its Result Type
Promise.allSettled waits for every input and never rejects. Each result is a PromiseSettledResult<T>, a union you narrow with the status field:
r.value only exists after the status check, because the rejected variant has no value. reason is any, for the same reason as in catch. The filter uses a type predicate so that the filtered array is typed as fulfilled results.
Wrapping a Callback API in a Promise
Older APIs report results through a callback, often in the Node style (err, result) => void. Wrap them once in a function that returns a typed promise, and the rest of the code can use await:
In Node, util.promisify does this for functions that follow the (err, result) convention, and many built-in modules already have promise versions (node:fs/promises, node:timers/promises).
Common Mistakes
- Returning
Twhere the signature saysPromise<T>, or the reverse. A non-async function declaredPromise<User>must return a promise; anasyncfunction returns one automatically. - Forgetting to handle a promise. A call like
save(user);withoutawait,thenorcatchcompiles fine, and a rejection becomes an unhandled rejection (which ends a Node process by default). The typescript-eslint ruleno-floating-promisescatches these. - Trusting the type of
.catch((e) => ...). Itseisany. Annotate it asunknown. - Using
new Promisearound something that already returns a promise. Just return orawaitthe existing promise.
Frequently Asked Questions
What is Promise<T> in TypeScript?
Promise<T> is the type of a promise that resolves with a value of type T. A function returning Promise<string> hands back a promise whose then callback, or await, gives a string. A promise that resolves with no value is Promise<void>.
How do I type new Promise in TypeScript?
Pass the type argument: new Promise<number>((resolve, reject) => ...). Without it, TypeScript cannot infer the value from resolve calls and the result is Promise<unknown>. For a promise that resolves with nothing, use new Promise<void>(resolve => ...) so that resolve() with no argument is allowed.
What type is the error in a promise catch?
any. The catch callback's reason parameter is typed any in the standard library, because anything can be thrown or rejected. Annotate it as unknown yourself (.catch((e: unknown) => ...)) and narrow with instanceof Error before using it.
How does Promise.all work with types in TypeScript?
Promise.all on an array literal returns a tuple type with one element per input, in order: Promise.all([getUser(), getCount()]) is Promise<[User, number]>, so destructuring gives each value its own type. On an array of the same type, T[], it returns Promise<T[]>.
What is the difference between Promise.all and Promise.allSettled?
Promise.all rejects as soon as any input rejects. Promise.allSettled always resolves, with an array of PromiseSettledResult<T> objects: { status: "fulfilled", value } or { status: "rejected", reason }. Check status to narrow each one.