A TypeScript Promise represents work whose result will be available later. Write it as Promise<T>, where T is the type of the eventual fulfillment value—not a value you can use immediately. Await or chain the Promise before passing that value to synchronous code; choose a concurrency helper according to whether you need every result, any success, or the first settlement.
What a Promise represents
A Promise is an object representing the eventual outcome of an operation. It begins pending and can become fulfilled with a value or rejected with a reason. Fulfilled and rejected Promises are settled. “Resolved” is not always synonymous with “fulfilled”: a Promise may be resolved by being committed to follow another Promise’s eventual outcome, which could still be a rejection. MDN’s Promise reference describes the states and resolution behavior.
As an Amazon Associate I earn from qualifying purchases.
A Promise is not a thread, and await does not freeze the whole program. It suspends progress in the current async function while the runtime and underlying operation continue their work; control returns to the caller until the function can resume.
Quick wins for a faster PC:
Fix the driver behind crashes, sound loss and screen glitchesFind Drivers →Repair Windows errors before they cause bigger problemsFix Now →Scan for outdated or missing drivers - takes under a minuteDriver Scan →What Promise<T> means in TypeScript
The type parameter describes the fulfillment value. For example, Promise<number> means that if the Promise fulfills, its value is a number. It does not mean the number is already available, nor does the type itself perform or validate the operation at runtime.
#1 Best Overall
async function loadCount(): Promise<number> {
return 3;
}
const countPromise = loadCount(); // Promise<number>
async function showCount(): Promise<void> {
const count = await countPromise; // number
console.log(count);
}
TypeScript can flag mistakes such as passing a Promise<User> to a function that expects a User>, accessing a property on a Promise before obtaining its value, or treating a Promise as a resolved boolean. The TypeScript 3.6 release notes include the diagnostic prompt, “Did you forget to use the await keyword?” The TypeScript 3.6 release notes document that diagnostic. These checks are static: untyped JavaScript, incorrect declarations, or other runtime data can still violate the type contract.
Unwrapping with Awaited<T>
TypeScript’s Awaited<T> utility models the type produced by awaiting a value or following a thenable. It recursively unwraps nested Promises: for example, Awaited<Promise<string>> is string. It describes a type relationship; it does not wait for anything at runtime. The utility was introduced in TypeScript 4.5, whose release notes also connect it to improved modeling of Promise.all and related built-ins. TypeScript 4.5 release notes.
Tuple inference and historical compiler notes
TypeScript 3.9 documented a correction to Promise.all inference for tuples: an element that could be undefined should not make a separate, known element appear optional. This is a historical note about that release, not evidence that current compilers retain the old behavior. TypeScript 3.9 release notes.
What’s actually slowing this PC down?
Pick the symptom - the matching free tool is one click away.
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
Using await or .then()
An async function always returns a Promise, even when its body returns an ordinary value. An exception that escapes the function rejects that returned Promise. As MDN puts it, “Async functions always return a promise.” MDN’s async function reference.
Use await for step-by-step work
await makes a sequence of asynchronous steps read much like ordinary control flow. A rejected awaited Promise behaves like a thrown exception at that point, so local try/catch is often straightforward:
async function getUserName(): Promise<string> {
try {
const response = await fetch("/api/user");
if (!response.ok) {
throw new Error(`Request failed: ${response.status}`);
}
const user: { name: string } = await response.json();
return user.name;
} catch (error) {
// Handle the failure here or rethrow it for the caller.
throw error;
}
}
This is an illustrative pattern, not runtime validation of the response body. The type annotation on user does not check the JSON at runtime; validate untrusted response data before relying on its shape. Also, fetch generally fulfills for HTTP error responses such as 404, so check response.ok or status when those outcomes should count as failures.
Use chaining to transform or compose results
Chaining is useful when a Promise’s result flows directly into another transformation or API call:
Free tools Windows power users keep installed
One-click scans. No signup required.
getUser()
.then((user) => user.name)
.catch((error) => {
reportError(error);
throw error;
});
Each .then() returns a new Promise. A fulfillment handler’s return value becomes the next fulfillment value; if it returns a Promise or other thenable, the chain follows that outcome. If the handler throws, the next Promise rejects. A rejection handler that returns normally handles the failure and makes the next Promise fulfill with its return value. Rethrow when the caller must still see the failure. MDN’s then() reference.
Choose await when local sequencing and exception handling make the flow clearer; choose chaining when direct transformation or composition is more natural. In either case, the caller still needs to handle, return, or otherwise account for the resulting Promise.
Handling rejection paths
A started Promise can reject even if its result is ignored. Make responsibility explicit: await it within a guarded path, return it to a caller that will handle it, or attach a rejection handler with an intentional recovery or reporting action.
- With
await: usetry/catcharound the operation when this function should handle the failure. If it cannot recover, rethrow so the returned Promise remains rejected. - With a chain: a terminal
.catch()can handle failures not recovered earlier. Returning a fallback value means the resulting chain fulfills with that fallback; throwing again preserves rejection. - For cleanup: use
.finally()for work that should run after either fulfillment or rejection. Avoid letting cleanup throw or return a rejected Promise unintentionally if that would replace the original outcome.
Do not silently swallow a rejection unless the fallback is an intentional part of the function’s behavior. The chain behavior of handlers is detailed in MDN’s Promise reference.
Choosing a Promise concurrency helper
These helpers coordinate Promises; they do not themselves start arbitrary work. To overlap independent operations, create their Promises before awaiting the combined result. If you await the first operation before starting the second, the work is sequential.
Best Value
| Helper | Settlement rule | Use it when |
|---|---|---|
Promise.all(inputs) |
Fulfills with all fulfillment values when every input fulfills; rejects if an input rejects. | Every result is required to continue. |
Promise.allSettled(inputs) |
Fulfills after every input settles, reporting each outcome as fulfilled or rejected. | You need to inspect or report each success and failure independently. |
Promise.any(inputs) |
Fulfills with the first fulfillment; rejects if all inputs reject. | Any one successful result is sufficient. |
Promise.race(inputs) |
Settles with the outcome of the first input to settle, whether fulfilled or rejected. | The earliest completion, of either kind, should determine the result. |
These are different failure and result policies, not interchangeable “run in parallel” options. MDN’s Promise reference documents their settlement behavior.
Start independent operations before awaiting
async function loadDashboard() {
const profilePromise = loadProfile();
const alertsPromise = loadAlerts();
const [profile, alerts] = await Promise.all([
profilePromise,
alertsPromise,
]);
return { profile, alerts };
}
Both operations are initiated before the combined Promise is awaited. If every result is required, Promise.all expresses that requirement directly. If each outcome must be processed even when some fail, use Promise.allSettled. For independent Promises that may reject, attach timely handling rather than leaving one rejection unobserved while waiting on another.
A race is not cancellation
Promise.race determines which outcome the race reports; it does not stop the other operations. A losing operation can keep running. Where the underlying API supports cancellation, use its cancellation mechanism—for example, an AbortSignal with supported web APIs—and connect that to your timeout or decision logic. A Promise alone does not provide a universal way to cancel its underlying work. MDN’s Promise reference.
Common Promise mistakes in TypeScript
- Passing
Promise<T>whereTis expected: await or chain to obtain the fulfillment value, or change the receiving function’s contract to accept asynchronous input. - Reading a value’s property from the Promise: access the fulfillment value after
awaitor inside a fulfillment handler. - Checking a Promise as if it were a boolean result: await the boolean Promise or inspect its fulfilled value in
.then(). A Promise object’s truthiness does not reveal the eventual boolean. - Awaiting independent calls one at a time: create the Promises first, then await a combinator such as
Promise.allwhen all results are needed. - Ignoring a started Promise: ensure a responsible caller receives it or attach meaningful rejection handling.
- Assuming a type annotation supplies runtime support: TypeScript types do not add a Promise implementation to the environment.
Runtime support and top-level await
Keep three concerns separate: TypeScript syntax transformation, the library declarations used for type checking, and the APIs available in the deployed runtime. Historical TypeScript 1.6 documentation described async function support as relying on a compatible Promise implementation for its supported output. That is a version-specific historical statement, not a current compatibility matrix; check the documentation for the actual runtime and build target you deploy. TypeScript 1.6 release notes.
Top-level await also depends on module context and build configuration. MDN documents it in JavaScript modules, and TypeScript 4.5 identified module: es2022 as a stable target for top-level await at that time. That versioned compiler guidance does not guarantee support in every bundler or runtime; verify the combination used by your project. MDN’s await reference and TypeScript 4.5 release notes.
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.




