02 - Functions
📋 Jump to TakeawaysBasic Function Syntax
Type the parameters and the return value:
function add(a: number, b: number): number {
return a + b;
}
// Arrow function — same thing
const multiply = (a: number, b: number): number => a * b;The return type is often inferred — you can omit it if it's obvious:
function add(a: number, b: number) { // return type inferred as number
return a + b;
}void and never
// void — function doesn't return anything
function log(message: string): void {
console.log(message);
}
// never — function never completes (throws or infinite loop)
function throwError(message: string): never {
throw new Error(message);
}Optional and Default Parameters
// Optional — might not be passed (becomes undefined)
function greet(name: string, greeting?: string): string {
return `${greeting || "Hello"}, ${name}`;
}
greet("Alice"); // "Hello, Alice"
greet("Alice", "Hi"); // "Hi, Alice"
// Default — uses a fallback value if not passed
function createUser(name: string, age: number = 18) {
return { name, age };
}
createUser("Bob"); // { name: "Bob", age: 18 }
createUser("Bob", 25); // { name: "Bob", age: 25 }Rest Parameters
Collect any number of arguments into an array:
function sum(...numbers: number[]): number {
return numbers.reduce((acc, n) => acc + n, 0);
}
sum(1, 2, 3); // 6
sum(1, 2, 3, 4, 5); // 15Function Types
Define the shape of a function — useful for callbacks:
type MathOperation = (a: number, b: number) => number;
const divide: MathOperation = (a, b) => a / b; // types inferred from MathOperationCallback Types
When a function takes another function as a parameter:
function fetchData(url: string, callback: (data: string) => void): void {
// ... fetch data
callback("result");
}
// Or define the callback type separately
type OnComplete = (success: boolean) => void;
function save(data: string, onComplete: OnComplete): void {
// ... save data
onComplete(true);
}Overloads
Same function name, different parameter types. Use overloads when the return type depends on the input type — if the return type is always the same, a union parameter is simpler:
// Union parameter is enough when return type doesn't change
function log(value: string | number): void {
console.log(value);
}
// Overloads are useful when return type depends on input type
function format(value: string): string;
function format(value: number): string;
function format(value: string | number): string {
if (typeof value === "string") {
return value.toUpperCase();
}
return value.toFixed(2);
}
format("hello"); // "HELLO"
format(3.14159); // "3.14"Overloads also work with different return types based on input:
function parse(input: string): string[];
function parse(input: string[]): string;
function parse(input: string | string[]): string | string[] {
if (typeof input === "string") {
return input.split(","); // string in → string[] out
}
return input.join(","); // string[] in → string out
}
parse("a,b,c"); // string[]
parse(["a", "b", "c"]); // stringThe implementation signature must be compatible with all overload signatures.
⚠️ Important: All overload signatures must appear directly above the implementation with no other code in between.
Key Takeaways
- Type parameters and return values
?makes a parameter optional,= valuegives it a defaultvoid= returns nothing,never= never returns- Use function types (
type Fn = (a: number) => string) for callbacks - Let TypeScript infer return types when obvious
- Rest parameters (
...numbers: number[]) accept any number of arguments as a typed array - Overloads let you define multiple signatures when the return type depends on the input type
- Inline callback typing:
callback: (data: string) => voiddirectly in parameters