Function Type Signatures & Function Overloads
Quick Overview
Overload signatures describe the callable shapes; the `implementation` signature sits beneath them and is not callable itself. Only the overloads are visible to callers, which is why the implementation can be loosely typed.
Deep Dive
1. Annotating Functions
Functions in TypeScript require parameter type annotations and optional return type annotations.
2. Function Signatures & Callback Types
You can define separate function type signatures for callbacks:
// Function type signature syntax: (arg1: Type, arg2: Type) => ReturnType
type SearchCallback = (query: string, limit: number) => string[];
const executeSearch: SearchCallback = (q, lim) => {
return [`Result for ${q} (max: ${lim})`];
};
3. Function Overloads
Sometimes a function can accept different combinations of arguments and return different result types depending on those arguments. Function Overloads allow you to define multiple public function signatures followed by a single implementation signature:
// Overload Signature 1: Pass a timestamp number
function makeDate(timestamp: number): Date;
// Overload Signature 2: Pass year, month, day numbers
function makeDate(year: number, month: number, day: number): Date;
// Single Implementation Signature (Internal)
function makeDate(yearOrTimestamp: number, month?: number, day?: number): Date {
if (month !== undefined && day !== undefined) {
return new Date(yearOrTimestamp, month - 1, day);
}
return new Date(yearOrTimestamp);
}
const d1 = makeDate(1600000000000); // Calls Overload 1
const d2 = makeDate(2026, 8, 28); // Calls Overload 2
4. Visual Overload Resolution
[ Caller Invocation ] ──> makeDate(2026, 8, 28)
│
▼
[ Signature Matching ] ──> Matches Overload #2 (3 numbers) -> Returns Date
5. Common Mistakes
- Exposing Implementation Signature Directly: Callers can ONLY see the overload signatures, NOT the internal implementation signature! Make sure your overload signatures cover all intended public use cases.
6. Next Steps
Use overloads for complex API helper functions. Next, let's compare Enums versus Const Assertions!
Next Up in TypeScript & Type System Mechanics
TypeScript Primitives & Explicit Type Annotations
TypeScript erases entirely at build time, so a `string` annotation produces no runtime check whatsoever. A value arriving from an API is whatever the server actually sent, regardless of what the annotation claims.
Type Inference & Literal Types (const vs. let)
`let x = "GET"` infers `string` because the binding can change; `const x = "GET"` infers the literal `"GET"`. That widening rule is why object properties need `as const` to stay narrow.
Arrays, Tuples & Readonly Modifiers
`string[]` is any number of strings; `[string, number]` is exactly two, in that order. `readonly` removes the mutating methods at compile time, so `push` becomes a type error rather than a runtime surprise.
