Function Overloading in TypeScript


Function Overloading in TypeScript#
Function overloading lets you define multiple function signatures for a single implementation. This is useful when a function can be called with different argument types or counts, and you want TypeScript to understand these variations clearly.
What is Function Overloading?
In TypeScript, function overloading means declaring multiple function signatures (overload signatures) for a function, followed by a single implementation that handles all cases.
This allows callers to get accurate type checking and IntelliSense based on how they call the function.
Writing Overload Signatures
Overload signatures declare the different ways a function can be called:
function combine(a: string, b: string): string;
function combine(a: number, b: number): number;These signatures declare that combine can take either two strings or two numbers.
Implementation Signature
After the overload signatures, you write a single implementation signature that covers all cases:
function combine(a: string | number, b: string | number): string | number {
if (typeof a === "string" && typeof b === "string") {
return a + b;
}
if (typeof a === "number" && typeof b === "number") {
return a + b;
}
throw new Error("Invalid arguments");
}The implementation signature is not visible to callers; only the overload signatures are.
Practical Examples
Example: Combining Strings or Numbers
function combine(a: string, b: string): string;
function combine(a: number, b: number): number;
function combine(a: string | number, b: string | number): string | number {
if (typeof a === "string" && typeof b === "string") {
return a + b;
}
if (typeof a === "number" && typeof b === "number") {
return a + b;
}
throw new Error("Invalid arguments");
}
const result1 = combine("Hello, ", "world!"); // string
const result2 = combine(10, 20); // numberExample: Overloading with Different Parameter Counts
function formatDate(date: Date): string;
function formatDate(date: Date, locale: string): string;
function formatDate(date: Date, locale?: string): string {
return locale ? date.toLocaleDateString(locale) : date.toLocaleDateString();
}
formatDate(new Date()); // uses default locale
formatDate(new Date(), "en-US"); // uses specified localeBest Practices
- Always declare overload signatures before the implementation.
- Keep overload signatures as specific as possible.
- Use the implementation signature to handle all cases safely.
- Throw errors or handle unexpected inputs gracefully in the implementation.
- Document each overload signature clearly.
Tip: Overloads improve developer experience by providing precise type information for different call patterns.
Common Pitfalls
- Forgetting to declare overload signatures before the implementation.
- Making the implementation signature too broad or too narrow.
- Returning types in the implementation that don't match any overload.
- Not handling all overload cases in the implementation, leading to runtime errors.
Warning: TypeScript only checks calls against overload signatures, not the implementation signature.
Next Steps
Next, learn about arrow functions and how the this context behaves differently compared to regular functions.
Questions about function overloading? Share your thoughts or examples in the comments!