Function Types & Callbacks

Beginner · 17 min read · ▶ live playground · ✦ checkpoint

Function types describe functions as values: what inputs they accept and what return value callers may use. They are how TypeScript checks callbacks, shared rules, and small pieces of behavior you pass into other functions.

Function values have shapes

A function value is a function stored in a variable or passed as an argument. A function type expression is the type syntax for that value, written like (message: string) => void.

Read this shape left to right:

  • (userName: string, karma: number) describes the parameters.
  • => string describes the return value.
typescript — playgroundtype-checked
⌘/Ctrl + Enter to run

The arrow functions do not annotate userName or karma. They get contextual typing, meaning TypeScript uses the surrounding BadgeFormatter promise to type the parameters. The middle still uses inference; the boundary is the type alias.

This is the same label idea from arrays and objects. The value is a function, so the label describes its call shape: what can go in, and what can come out.

Passing functions to functions

A callback is a function you pass to another function so that other function can call it. A higher-order function is a function that accepts another function or returns one.

Here, listLaunches accepts a callback named shouldInclude:

typescript — playgroundtype-checked
⌘/Ctrl + Enter to run

LaunchRule says the callback receives one Launch and returns a boolean. That lets listLaunches ask a yes-or-no question for each launch.

The inline callback in the second console.log gets the same contextual typing. TypeScript knows launch.owner is a string because shouldInclude must be a LaunchRule.

Object types can be callable

A callable value is a value you can call with parentheses. A call signature is a function promise written inside an object type, using : before the return type.

The function type expression (message: string) => void can also be written as a call signature:

typescript — playgroundtype-checked
⌘/Ctrl + Enter to run

For a simple function shape, the arrow type is shorter. The object form matters because code you read later may describe values with call signatures inside larger object shapes. You do not need the larger pattern yet; you just need to read this as "this value can be called with a string message."

void callbacks can return values

void means the caller should not use the return value. That rule has one beginner-surprising consequence: a function returning a value can be accepted where a callback type returns void.

A side effect is work a function does besides returning a value, like pushing into an array or logging.

typescript — playgroundtype-checked
⌘/Ctrl + Enter to run

The callback returns the number from nameLengths.push(...). visitLaunches ignores it, so the callback still fits VisitLaunch. The useful work is the side effect: the array changed.

That flexibility belongs to callback compatibility. Inside a function whose own return is annotated void, returning a value is still an error:

function recordVisit(name: string): void {
  return name.length;
}

→ playground.ts:2:3 - error TS2322: Type 'number' is not assignable to type 'void'.

The rule to keep

Use function type expressions when a function travels as a value. Use higher-order functions when one piece of code needs behavior supplied by another piece. Read call signatures as callable object shapes, and remember that void callback returns are ignored by the caller.

Next, one function starts accepting several call shapes. When a single function type cannot describe those shapes cleanly, overloads give callers separate promises for each way to call it.

Checkpoint

Answer all three to mark this lesson complete

+50 XP on completion