iwantcoding.com
🔥 Daily 👥 Rooms 🏆 Top Log in Sign up

TS Return Types

Return type annotations turn "what does this give back?" into a compiler-checked contract. Most of the time TS infers them — you write them for the boundaries that matter.

Explicit

TS
function add(a: number, b: number): number {
    return a + b;
}

Inferred

TS
function double(x: number) {
    return x * 2;   // inferred: number
}

void — no useful return

TS
function log(msg: string): void {
    console.log(msg);
}

Never — function doesn't return

TS
function fail(msg: string): never {
    throw new Error(msg);
}

Union returns

TS
function divide(a: number, b: number): number | null {
    if (b === 0) return null;
    return a / b;
}

Async returns

An async function always returns a Promise<T>:

TS
async function getUser(id: number): Promise<User> {
    const res = await fetch(`/api/users/${id}`);
    return res.json();
}

When to annotate

AnnotateSkip (let TS infer)
Exported functions / public APIsSmall inline callbacks
Functions you want to prevent changingSingle-expression arrow functions
Functions returning unionsFunctions delegating to a well-typed helper
Tip: Turn on noImplicitReturns in tsconfig — TS will warn if a function has paths that don't return when others do. Catches "forgot to return inside the if".

Example

Example
function divide(a: number, b: number): number | null {
  if (b === 0) return null;
  return a / b;
}
const r = divide(10, 0);
if (r !== null) console.log(r.toFixed(2));
Try it Yourself »

Exercise

Annotate the return type as a Promise of User.

async function getUser(): {}

Test yourself

Q1. An async function returns a…
Q2. noImplicitReturns errors when…
Q3. A function that errors out on failure but returns on success often returns…

Discussion

Loading…