TS Function Overloads
Function overloads let one function declare several call signatures. Useful when the return type depends on the argument type — and a union return would lose that link.
The shape
TS
// Overload signatures
function pick(x: string): string;
function pick(x: number): number;
// Implementation signature (not callable from outside)
function pick(x: string | number): string | number {
return typeof x === 'string' ? x.toUpperCase() : x * 2;
}
const a = pick('hi'); // string
const b = pick(21); // number
Without overloads, the return type would be the wider string | number — and callers would have to narrow it on every use.
When you need them
- Return type depends on the shape of the input.
- You want to disallow some combinations.
- You're typing an existing JS API.
Often, generics are simpler
TS
function pick<T extends string | number>(x: T): T {
return x;
}
const a = pick('hi'); // 'hi' — even narrower!
const b = pick(21); // 21
Method overloads on a class
TS
class Greeter {
say(person: string): string;
say(persons: string[]): string[];
say(p: string | string[]): string | string[] {
return Array.isArray(p) ? p.map(x => `Hi, ${x}`) : `Hi, ${p}`;
}
}
Rules
- Overload signatures sit above the implementation.
- The implementation signature must be compatible with all overloads.
- The implementation signature is not visible to callers.
- Order matters — TS picks the first matching overload.
Tip: Reach for generics first; reach for overloads when the relationship between input and output really needs spelling out. Less surface area = fewer bugs.
Example
Example
function pick(x: string): string;
function pick(x: number): number;
function pick(x: string | number): string | number {
return typeof x === 'string' ? x.toUpperCase() : x * 2;
}
console.log(pick('hi')); // string
console.log(pick(21)); // number
Try it Yourself »
Exercise
A simpler alternative to overloads is often…
Use
Eight letters.
Discussion
Loading…