Function overloads
Declares several call signatures for one function so callers see only the shapes you intend.
function name(a: A): R1;
function name(a: B, b: C): R2;
function name(a: A | B, b?: C): R1 | R2 {
// implementation — not visible to callers
}- Added in TypeScript 1.0
Parameters
| Parameter | Type | Description |
|---|---|---|
$overload signatures | declaration list | Two or more bodyless signatures written directly above the implementation. These are the only signatures callers can use, and they are matched in source order. |
$implementation signature | declaration with body | The single signature that carries the body. It must be compatible with every overload above it, and it is invisible from the outside. |
Return value
R1 | R2Each call resolves to the return type of the first overload signature that matches the arguments; the implementation's return type is never what a caller sees.
Errors
An implementation signature incompatible with an overload signature is an error ("This overload signature is not compatible with its implementation signature"), and a call whose argument type spans two overloads fails with "No overload matches this call".
Changelog
- PHP 1.0Overload signatures supported for functions, methods and constructors.
- PHP 4.7Instantiation expressions let a caller pin a generic overload without calling it, which removes some cases that previously needed an extra overload.
Write two or more bodyless signatures, then one implementation carrying the body. Callers see only the bodyless signatures; TypeScript picks the first one whose parameters match and reports its return type.
When to reach for it
- The number of arguments changes the meaning —
makeDate(timestamp)versusmakeDate(month, day, year). - The return type is genuinely tied to the argument type in a way a union cannot express.
- You are describing an existing JavaScript API whose shape you cannot change.
What trips people up
Three things, in order of how often they bite. First, the implementation signature is invisible: if you write one overload plus a broad implementation, callers get the overload only, and fn() fails even though the body accepts zero arguments. Second, overloads do not accept union arguments — len(cond ? "hi" : [1]) fails with No overload matches this call, because no single signature covers both branches. The handbook's rule is blunt: always prefer parameters with union types instead of overloads when possible. Reach for overloads only when the argument count varies or the return type must follow the input. Third, the implementation must be compatible with every overload, and widening it to any to silence that check throws away the safety you were buying.
Example
When to use it
- Type a function that accepts either one packed argument or several separate ones.
- Describe an existing JavaScript API whose return type changes with the argument type.
- Give a factory a precise return type per input kind instead of a union callers must narrow.
Frequently asked questions
Why can't I call my TypeScript function with the implementation signature?
Because the implementation signature is deliberately invisible to callers — only the bodyless overload signatures above it are callable. If you need the broader form, add it as an explicit overload signature; a function with a single overload is strictly narrower than its body suggests.
Why does TypeScript say 'No overload matches this call'?
Usually because the argument's type is a union that no single overload covers, since resolution matches one signature at a time rather than splitting a union across several. Either replace the overloads with a union parameter or narrow the argument before the call.
When should I use overloads instead of union types?
Only when the number of arguments changes the meaning of the call, or when the return type must follow the argument type. The handbook's guidance is to always prefer union-typed parameters when they can express the same API, because overloads reject union-typed arguments.
More examples
When a union beats overloads
Prints "5 3" then 5. Both functions handle a plain string and a plain array, but only the union version accepts a value whose type is the union — overload resolution matches one signature at a time and never splits a union across two of them. This is the case the handbook has in mind when it says to prefer union parameters.
// Overloaded: rejects a value that might be either type
function lenOverloaded(s: string): number;
function lenOverloaded(arr: unknown[]): number;
function lenOverloaded(x: any): number { return x.length; }
// Union parameter: accepts the same calls and one more
function len(x: string | unknown[]): number { return x.length; }
const maybe: string | number[] = "hello";
console.log(lenOverloaded("hello"), lenOverloaded([1, 2, 3]));
console.log(len(maybe));
// lenOverloaded(maybe);
// Error: No overload matches this call.
// Overload 1 of 2 — Argument of type 'string | number[]' is not
// assignable to parameter of type 'string'.Overloads on a method, and the compatibility rule
Prints "ada 0 36". The second and third overloads let a caller supply a typed fallback and get that exact type back, while the first keeps the untyped lookup available. The commented-out signature shows the other half of the contract: every overload must be assignable to the implementation, so a numeric key is rejected before any caller sees it.
class Cache {
#store = new Map<string, unknown>();
get(key: string): unknown;
get(key: string, fallback: string): string;
get(key: string, fallback: number): number;
get(key: string, fallback?: unknown): unknown {
return this.#store.has(key) ? this.#store.get(key) : fallback;
}
set(key: string, value: unknown): this {
this.#store.set(key, value);
return this;
}
}
const c = new Cache().set("name", "ada").set("age", 36);
const name: string = c.get("name", "unknown") as string;
console.log(name, c.get("missing", 0), c.get("age"));
// Rejected by tsc, because no call could ever reach it:
// get(key: number): boolean;
// Error: This overload signature is not compatible with its
// implementation signature.
Discussion