TYPESCRIPT / CHAPTER 11
Typed asynchronous results and explicit failure
AdvancedModel failure without confusing it with a missing return value.
By the end of this chapter
- Read Promise result types
- Narrow fulfilled domain-result unions
- Distinguish rejection from explicit error variants
The idea
Promise<T> describes the value obtained when a promise fulfills; it does not describe every possible rejection. An async function returning a number produces Promise<number>. Await extracts the fulfilled value but can throw on rejection, so callers still need a failure policy. Type annotations alone cannot prove a network operation succeeds.
Expected domain failures can instead be represented by a discriminated result inside the promise. The success variant contains data, while the error variant carries an explanation. Awaiting that promise gives the union, which must be narrowed before reading success-only fields. This does not eliminate unexpected exceptions: decide which errors become domain results and which propagate. Keep ordinary absence distinct from an accidentally omitted return.
type Lookup = {ok: true; value: number} | {ok: false; reason: string};
async function lookup(found: boolean): Promise<Lookup> {
return found ? {ok: true, value: 6} : {ok: false, reason: "missing"};
}
async function main() {
const result = await lookup(false);
console.log(result.ok ? result.value : result.reason);
}
main();missing
After await, the discriminant controls which field is safe to read.
Try it yourself
Write a typed asynchronous parser that returns a failure variant for invalid input while allowing unexpected I/O failures to reject.
Use your own editor for this exercise. Runnable challenges on CodeQuest are available for JavaScript, Python, and SQL.
CHECK YOUR UNDERSTANDING