Welcome back! I am Mihir, and in this lesson we will learn function overloading in TypeScript.
Function overloading lets one function support multiple call patterns while still giving callers strong type checking.
The Problem
Sometimes a function can accept different types of input.
function format(value: string | number): string {
if (typeof value === "string") {
return value.trim();
}
return value.toFixed(2);
}This works, but the function signature only says:
string | numberOverloads let you describe each valid call more clearly.
Basic Function Overload
function format(value: string): string;
function format(value: number): string;
function format(value: string | number): string {
if (typeof value === "string") {
return value.trim();
}
return value.toFixed(2);
}The first two lines are overload signatures.
The last function is the implementation signature.
Calling an Overloaded Function
const name = format(" Mihir ");
const price = format(99.5);Both calls are valid.
Invalid:
format(true);TypeScript rejects this because there is no overload for boolean.
Overloads with Different Return Types
Overloads are especially useful when different inputs return different types.
function getValue(value: string): string;
function getValue(value: number): number;
function getValue(value: string | number): string | number {
return value;
}
const username = getValue("mihir");
const score = getValue(100);TypeScript knows:
username; // string
score; // numberImplementation Must Handle All Overloads
The implementation signature must be broad enough to support every overload.
function double(value: string): string;
function double(value: number): number;
function double(value: string | number): string | number {
if (typeof value === "string") {
return value + value;
}
return value * 2;
}The implementation uses string | number because it must handle both cases.
Overloads with Multiple Parameters
function createUser(name: string): { name: string };
function createUser(name: string, age: number): { name: string; age: number };
function createUser(name: string, age?: number) {
if (age === undefined) {
return { name };
}
return { name, age };
}Usage:
const userOne = createUser("Mihir");
const userTwo = createUser("Mihir", 28);Overloads vs Union Parameters
Use a union when the return type does not depend heavily on the input.
function printId(id: string | number): void {
console.log(id);
}Use overloads when the call pattern affects the return type.
function parseInput(value: string): string[];
function parseInput(value: number): number[];
function parseInput(value: string | number): string[] | number[] {
if (typeof value === "string") {
return value.split(",");
}
return [value];
}Common Mistake
Do not expose an overload that the implementation cannot safely support.
function convert(value: string): number;
function convert(value: boolean): number;
function convert(value: string | boolean): number {
return Number(value);
}This compiles, but the boolean overload may be confusing for callers. Overloads should describe useful and intentional behavior.
Quick Recap
- Function overloads describe multiple valid ways to call one function.
- Overload signatures are written above the implementation.
- The implementation signature must handle every overload.
- Use overloads when different inputs produce different return types.
- Use unions for simpler cases.
Next up, we move into Type Aliases →, where you will learn how to give reusable names to object shapes, unions, function types, and more.