iTechGuides is reader-supported. When you buy through links on our site, we may earn an affiliate commission. As an Amazon Associate I earn from qualifying purchases. Learn more
A TypeScript Promise is a value that represents an operation whose result will become available later. Promise<T> describes the type of its eventual fulfillment value, not a value you can use immediately: await the Promise or chain from it before treating the result as T. Choose await or .then() to consume the result, handle rejections deliberately, and use the Promise combinator whose settlement rule matches the work.
What a Promise represents
A Promise is an object representing the eventual outcome of an asynchronous operation. It can be pending, fulfilled with a value, or rejected with a reason. Fulfilled and rejected Promises are settled; a pending Promise may transition to either outcome.
“Resolved” is not always a synonym for “fulfilled.” A Promise can be resolved by being committed to follow another Promise or thenable, while that followed operation is still pending. The outer Promise is settled only when the outcome it follows settles.
A Promise is not a thread. Awaiting one does not block the entire program. At an await expression, the current async function suspends and yields control to its caller; the function’s continuation can resume after the awaited operation settles. The runtime and the operation determine what work is actually being performed.
#1 Best Overall
What Promise<T> means in TypeScript
The generic type parameter T describes a Promise’s fulfillment value. It does not make that value available synchronously, and it does not describe the rejection reason.
async function loadCount(): Promise<number> {
return 3;
}
const countPromise = loadCount(); // Promise<number>
const count = await countPromise; // number, inside async code
An async function call returns a Promise, even when the function returns an ordinary value. In this example, loadCount() returns a Promise<number>; awaiting that Promise produces a number within the async function doing the await.
TypeScript can catch common mismatches, such as passing Promise<User> to a function that expects User, reading a property from Promise<Response> before obtaining its fulfillment value, or testing a Promise as though it were an already-resolved boolean. The TypeScript 3.6 release notes phrase one such diagnostic as: “Did you forget to use the await keyword?”
Promise<T> is a compiler-facing type contract, not runtime validation or execution. It does not resolve the operation or verify that a value arriving from untyped JavaScript or an inaccurate declaration really has type T. TypeScript’s checks help keep code consistent with its declarations; runtime behavior still depends on the actual value and operation.
Rank #2
- TypeScript implements a superset of syntax for strictly typed development, facilitating deep static analysis and enhanced development environment integration. The compiler translates source into standard script formats, ensuring parity across any runtime.
- TypeScript is ideal for front-end developers, full-stack engineers, and software architects who build large-scale web applications. It serves those looking to improve code excellence, reduce bugs through static checking, and maintain complex projects more.
- Lightweight, Classic fit, Double-needle sleeve and bottom hem
Unwrapping with Awaited<T>
TypeScript’s Awaited<T> utility describes the type obtained by recursively awaiting a value. It was introduced in TypeScript 4.5. For example, Awaited<Promise<string>> is string, and nested Promises are unwrapped recursively. A union can retain members that are not Promises. This is a type-level description; it does not perform asynchronous work at runtime.
Tuple inference in Promise.all
TypeScript 3.9 documented an inference correction for Promise.all with tuple values: if one element might be undefined, that optionality should not incorrectly make a different, known element optional. This is historical release-note context, not evidence that the old inference problem persists in current TypeScript versions.
Consume a Promise with await or .then()
Both await and Promise chaining consume Promise-based work while preserving asynchronous behavior. Use await when a function has a sequence of steps or local try/catch handling makes the flow clearer. Use .then() when a chain of transformations or an API’s Promise-oriented composition reads naturally.
Do these 3 things before closing this tab:
1Repair Windows errors before they cause bigger problems2Fix the driver behind crashes, sound loss and screen glitches3Clear out junk files and repair common Windows errorsUse await for sequential steps
async function getUserName(): Promise<string> {
const response = await fetch("/api/user");
const user: { name: string } = await response.json();
return user.name;
}
This illustrates the shape of the flow, not a complete production API client. Validate the response body at runtime if its contents are not already trusted, and check the API’s documented error behavior: for example, an unsuccessful HTTP status does not necessarily make fetch reject. An async function’s returned Promise fulfills with its returned value, follows a returned thenable, or rejects if an exception escapes the function.
MDN summarizes the key rule: “Async functions always return a promise.”
Use .then() to transform a result
getUser()
.then((user) => user.name)
.catch((error) => {
reportError(error);
throw error;
});
Each .then() returns a new Promise. A fulfillment handler’s returned value becomes the next Promise’s fulfillment value; if it returns a Promise or another thenable, the next Promise follows that outcome. If the handler throws, the next Promise rejects. A rejection handler that returns normally handles the rejection and makes the next Promise fulfill with its return value. Rethrow when the failure should continue propagating.
Handle rejection paths intentionally
A rejection is part of a Promise’s outcome, so make clear which caller or handler is responsible for it. When calling a Promise-returning function, choose one of these approaches:
Quick wins for a faster PC:
Clear out junk files and repair common Windows errorsFree Scan →Fix the driver behind crashes, sound loss and screen glitchesFind Drivers →- Await it inside a
try/catchwhen this function can handle or translate the failure. - Return the Promise so the caller can handle its rejection.
- Attach a meaningful rejection handler when the operation is intentionally managed as a chain.
Starting a Promise and then ignoring its return value can leave a rejection without a visible handler. Avoid swallowing errors unless an intentional fallback or recovery makes the failure handled.
Choose whether to recover or rethrow
A .catch() can handle a rejection by returning a fallback value; the resulting chain then fulfills with that value. If the caller must still see the failure, rethrow it. A final .catch() is a useful place to handle failures that earlier steps did not recover, but it should not silently convert failures into success unless that is the intended behavior.
In an async function, a rejected Promise awaited with await behaves like an exception at that point. Use try/catch for local recovery or translation; an uncaught exception rejects the async function’s returned Promise.
Use finally() for cleanup
finally() is appropriate for cleanup that should run after either fulfillment or rejection, such as releasing a resource. Keep its work from accidentally changing the outcome: if the cleanup itself throws or returns a rejected Promise, that failure can affect the Promise returned by the chain.
Choose the right Promise concurrency helper
Pick a combinator based on what the caller needs and what should happen when operations fail. These methods coordinate Promises; they do not themselves start work that has not already been started.
Best Value
| Helper | Settlement rule | Good fit |
|---|---|---|
Promise.all(inputs) |
Fulfills with all fulfillment values when every input fulfills; rejects if an input rejects. | Every result is required for the next step. |
Promise.allSettled(inputs) |
Fulfills after every input settles, with each outcome represented separately. | Report or process each success and failure independently. |
Promise.any(inputs) |
Fulfills with the first fulfillment; rejects if all inputs reject. | Any one successful result is enough. |
Promise.race(inputs) |
Settles according to the first input to settle, whether it fulfills or rejects. | The earliest completion of either kind should determine the result. |
Start independent work before awaiting
If operations do not depend on one another, start them before waiting for their results, then await a suitable combined Promise. Awaiting the first operation before starting the second makes the sequence serial.
async function loadDashboard() {
const profilePromise = loadProfile();
const alertsPromise = loadAlerts();
const [profile, alerts] = await Promise.all([
profilePromise,
alertsPromise,
]);
return { profile, alerts };
}
Use Promise.all here because both results are needed. If a started Promise can reject, ensure it has a timely and responsible rejection path; do not start independent work and then leave a failure unobserved while waiting elsewhere.
A race is not cancellation
Promise.race determines the outcome of the returned race Promise; it does not, by itself, stop the operations that did not win. Where the underlying API supports cancellation, use its cancellation mechanism, such as an AbortSignal, when stopping unnecessary work matters. Otherwise, a losing operation may continue running even though the race has already settled.
Free tools Windows power users keep installed
One-click scans. No signup required.
Common TypeScript Promise mistakes
- Passing a Promise where its value is expected. A function expecting
Tcannot use aPromise<T>as though it were already the fulfillment value. Await it, chain from it, or change the receiving function’s contract to accept asynchronous work. - Accessing a result too early. A property belongs to the fulfillment value, not to the Promise object. Await or use
.then()before accessing it. - Testing a Promise as a boolean. Await a Promise that fulfills with a boolean or test the value in a fulfillment handler. A Promise object itself is not the resolved boolean.
- Awaiting independent operations one at a time. Start independent operations first and combine them with the helper that matches the required result and failure behavior.
- Leaving a started Promise’s rejection unhandled. Await it in a guarded path, return it to a caller responsible for handling it, or attach an appropriate rejection handler.
- Assuming a type annotation supplies runtime support. TypeScript’s Promise types do not add a Promise implementation to the execution environment.
Runtime support, compiler output, and top-level await
Keep three concerns separate: whether the compiler accepts async syntax, what JavaScript it emits for the selected target, and whether the runtime supplies the APIs the emitted code uses. TypeScript’s historical 1.6 documentation described async function support as relying on a compatible Promise implementation for its supported output. That historical statement is not a current runtime compatibility matrix; check the documentation for the actual runtime and build configuration you deploy.
Top-level await also depends on module context. MDN documents it for JavaScript modules. TypeScript 4.5 release notes identified module: "es2022" as a stable target for top-level await at that time. That versioned compiler guidance is not a guarantee for every bundler, module setup, or runtime; verify the requirements of the toolchain in use.
Quick Recap
Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.

