Function Type Annotations
Function Type Annotations
Basic Function Types
// Explicit parameter and return types
function add(a: number, b: number): number {
return a + b;
}
// Arrow function
const multiply = (a: number, b: number): number => a * b;
// Return type inference (usually fine for simple functions)
const subtract = (a: number, b: number) => a - b;
Void Return Type
function logMessage(msg: string): void {
console.log(msg);
// no return statement needed
}
// void functions cannot return values
function invalid(): void {
return 42; // Error
}
Function as Type
// Function type alias
type MathFn = (a: number, b: number) => number;
const add: MathFn = (a, b) => a + b;
const subtract: MathFn = (a, b) => a - b;
// Interface with function method
interface Calculator {
add(a: number, b: number): number;
subtract: (a: number, b: number) => number;
}
const calc: Calculator = {
add: (a, b) => a + b,
subtract: (a, b) => a - b
};
Optional and Default Parameters
Optional and Default Parameters
Optional Parameters
// Optional parameter must come after required parameters
function greet(name: string, greeting?: string): string {
return `${greeting ?? 'Hello'}, ${name}!`;
}
greet('Alice'); // 'Hello, Alice!'
greet('Alice', 'Hi'); // 'Hi, Alice!'
// Explicit undefined
function greet2(name: string, greeting?: string): string {
return `${greeting || 'Hello'}, ${name}!`;
}
Default Parameters
// Default parameters are optional and have type inferred
function createUser(
name: string,
role: string = 'user',
active: boolean = true
) {
return { name, role, active };
}
createUser('Alice'); // { name: 'Alice', role: 'user', active: true }
createUser('Bob', 'admin'); // { name: 'Bob', role: 'admin', active: true }
createUser('Carol', 'user', false);
Rest Parameters
function sum(...numbers: number[]): number {
return numbers.reduce((total, n) => total + n, 0);
}
sum(1, 2, 3); // 6
sum(1, 2, 3, 4, 5); // 15
// Rest with other parameters
function log(level: string, ...messages: string[]): void {
console.log(`[${level}]`, ...messages);
}
log('INFO', 'Server', 'started', 'on', 'port', '3000');
Function Overloads
Function Overloads
Function overloads allow multiple type signatures for a single function.
Basic Overloads
function format(value: string): string;
function format(value: number): string;
function format(value: Date): string;
function format(value: string | number | Date): string {
if (typeof value === 'string') return value.toUpperCase();
if (typeof value === 'number') return value.toFixed(2);
return value.toISOString();
}
format('hello'); // 'HELLO'
format(42); // '42.00'
format(new Date()); // '2024-01-15T...'
Complex Overloads
function createElement(tag: 'div'): HTMLDivElement;
function createElement(tag: 'span'): HTMLSpanElement;
function createElement(tag: 'input'): HTMLInputElement;
function createElement(tag: string): HTMLElement {
return document.createElement(tag);
}
const div = createElement('div'); // HTMLDivElement
const span = createElement('span'); // HTMLSpanElement
Overloads vs Union Types
// Union type approach (simpler)
function process(input: string | number): string {
return typeof input === 'string' ? input.toUpperCase() : input.toString();
}
// Overload approach (better when return types differ)
function process2(input: string): string;
function process2(input: number): number;
function process2(input: string | number): string | number {
return typeof input === 'string' ? input.toUpperCase() : input * 2;
}
const result1 = process2('hello'); // string
const result2 = process2(5); // number
Callbacks and Higher-Order Functions
Callback and Higher-Order Functions
Typed Callbacks
// Callback parameter types
function fetchData(
url: string,
onSuccess: (data: unknown) => void,
onError: (error: Error) => void
): void {
// ...
}
fetchData(
'/api/users',
(data) => console.log(data),
(error) => console.error(error)
);
Higher-Order Functions
// Function that returns a function
function createMultiplier(factor: number): (value: number) => number {
return (value) => value * factor;
}
const double = createMultiplier(2);
const triple = createMultiplier(3);
double(5); // 10
triple(5); // 15
Generic Callbacks
function map<T, U>(array: T[], fn: (item: T, index: number) => U): U[] {
return array.map(fn);
}
const numbers = [1, 2, 3, 4, 5];
const doubled = map(numbers, (n) => n * 2); // number[]
const strings = map(numbers, (n) => n.toString()); // string[]
Common Patterns
// Middleware pattern
type Middleware = (
req: Request,
res: Response,
next: () => void
) => void;
function authMiddleware(req: Request, res: Response, next: () => void): void {
if (req.headers.authorization) {
next();
} else {
res.status(401).json({ error: 'Unauthorized' });
}
}
// Promise-based callback
function asyncOperation(): Promise<string> {
return new Promise((resolve) => {
setTimeout(() => resolve('done'), 1000);
});
}
asyncOperation().then((result) => console.log(result));