BeCuriouzLearn something new every day
Function Overloads: One Function, Many Shapes
💡 Function overloads expose several precise call signatures backed by one broad implementation, letting return types vary with argument types.
Sometimes a single function behaves differently depending on what you pass it, and you want the types to reflect that precisely. Function overloads let you declare multiple call signatures for one function, so TypeScript knows exactly which return type goes with which arguments.
You write two or more overload signatures (declarations with no body), followed by one implementation signature (with the body). Callers only ever see the overloads — the implementation signature is invisible from outside. Its job is just to be broad enough to handle every overload:
function len(x: string): number;
function len(x: any[]): number;
function len(x: string | any[]): number {
return x.length;
}
len("hello"); // 5
len([1, 2, 3]); // 3The real power shows when return types differ. Here the overloads promise a string for a string and a number for a number — something a single string | number return type could never express so precisely:
function double(x: string): string;
function double(x: number): number;
function double(x: any): any {
return typeof x === "string" ? x + x : x * 2;
}
const a = double("hi"); // typed as string → "hihi"
const b = double(4); // typed as number → 8One catch: the implementation signature must be compatible with every overload, but it is not itself callable. If you call double(true), TypeScript errors — even though any would technically accept it — because boolean matches none of the public overloads.