Overloads
Beginner · 16 min read · ▶ live playground · ✦ checkpoint
Overloads let one function offer several call shapes while keeping one implementation. Use them when different inputs should give callers different return types; reach for a union parameter when one clear shape is enough.
One function, several call shapes
An overload is a public call shape for one function. An overload signature is one of those public promises, written before the real function body.
Here, readMetric has two overload signatures:
The first overload says "karma" returns a number. The second says "owner" returns a string. The body handles both cases, but each caller gets the precise promise for the shape they used.
A union type is an either-or type written with |. Lesson 4.1 teaches unions properly next. For now, read "karma" | "owner" as "one of these two text values."
The implementation signature is the body contract
An implementation signature is the final signature with the function body. It must be wide enough for every overload above it.
In readMetric, the implementation accepts "karma" | "owner" and returns number | string because the body must cover both public shapes. The overload signatures are for callers. The implementation signature is for the body.
That split is the part people miss:
function readMetric(metric: "karma"): number;
function readMetric(metric: "owner"): string;
function readMetric(metric: "karma" | "owner"): number | string {
if (metric === "karma") {
return 42;
}
return "Mina";
}
function readQueuedMetric(metric: "karma" | "owner"): number | string {
return readMetric(metric);
}→ playground.ts:12:21 - error TS2769: No overload matches this call.
Overload 1 of 2, '(metric: "karma"): number', gave the following error.
Argument of type '"karma" | "owner"' is not assignable to parameter of type '"karma"'.
Type '"owner"' is not assignable to type '"karma"'.
Overload 2 of 2, '(metric: "owner"): string', gave the following error.
Argument of type '"karma" | "owner"' is not assignable to parameter of type '"owner"'.
Type '"karma"' is not assignable to type '"owner"'.
The fix is not to make the implementation wider. It already is. The fix is to choose a public shape that matches how callers really use the function.
Most of the time, a union is clearer
A union parameter is a parameter whose annotation is a union, like string | number. Use it when the return type is the same for each input shape.
This function accepts text or a number, and both paths return a string. Overloads would add ceremony without giving callers a better result.
Keep the rule plain:
- Use a union parameter when the function has one behavior and one return type.
- Use overloads when different call shapes need different return promises.
- If overloads make callers fight
TS2769, ask whether a union parameter is the better public promise.
Reading overloaded library types
A library type is type information for code you call but did not write. You will see overloads often in library types, especially when one function accepts many call shapes.
For example, the browser's document.createElement has overloads. The real TypeScript 5.9 DOM type uses a compact tag-name map form you learn later, plus a string fallback. As a simplified mental expansion, the idea looks like this:
createElement(tagName: "button"): HTMLButtonElement;
createElement(tagName: "canvas"): HTMLCanvasElement;
createElement(tagName: string): HTMLElement;The first line says a "button" tag gives a button element. The second says a "canvas" tag gives a canvas element. The wider string line is the fallback for tag names TypeScript cannot identify more specifically.
You do not need to memorize these. When you see repeated function lines with the same name and no body, read them as overload signatures: separate public promises for one implementation.
The rule to keep
Overloads are for one function with several public call shapes. The overload signatures are what callers see. The implementation signature must handle every overload, but it does not add another call shape for callers.
Section 4 starts the deeper model behind all of this: unions and literal types. Overloads are one way to express several possibilities, but unions are the core language for "one of these."
Checkpoint
Answer all three to mark this lesson complete