Typing Functions
Learn how to annotate function parameters and return types in TypeScript so your functions become self-documenting and error-proof by design.
Functions are the workhorses of any program — they take inputs, do something useful, and hand back a result. In plain JavaScript, a function will happily accept the wrong kind of input and silently do the wrong thing. TypeScript fixes that by letting you label every parameter and return value with a type. The moment you add those labels, TypeScript watches every call site and warns you before the code ever runs. That early warning system is one of the biggest reasons developers reach for TypeScript in the first place.
#Your First Typed Function
Adding types to a function is straightforward: write the type after the parameter name, separated by a colon, and write the return type after the closing parenthesis.
function greet(name: string): string {
return `Hello, ${name}!`;
}
console.log(greet("Ada"));
console.log(greet("World"));A function signature is a contract
Think of a typed function like a vending machine with labelled slots. The slot says 'coins only' — you cannot shove in a credit card and expect a snack. The return slot is also labelled: it promises to give you a specific item, not a mystery box. TypeScript enforces both promises at compile time, before anyone uses the machine.
#Multiple Parameters and Numeric Types
function add(a: number, b: number): number {
return a + b;
}
console.log(add(3, 7));
// add("3", 7); // TypeScript error: Argument of type 'string' is not assignable to parameter of type 'number'#Optional Parameters with ?
Sometimes a parameter is genuinely optional — it has a sensible absence. Mark it with ? after the name. Inside the function, TypeScript will remind you that the value could be undefined, so you need to handle that case.
function greetUser(name: string, title?: string): string {
if (title) {
return `Hello, ${title} ${name}!`;
}
return `Hello, ${name}!`;
}
console.log(greetUser("Turing"));
console.log(greetUser("Turing", "Dr."));#Default Parameters
A default parameter goes one step further: it provides a fallback value so you never have to guard against undefined inside the function. TypeScript infers the type from the default, so you usually do not need to write it explicitly.
function createMessage(text: string, prefix: string = "INFO"): string {
return `[${prefix}] ${text}`;
}
console.log(createMessage("Server started"));
console.log(createMessage("Disk full", "WARN"));Optional ? and default values are not interchangeable
A parameter with ? can be undefined inside the function body — you must check before using it. A parameter with a default value is never undefined inside the body, because TypeScript substitutes the default automatically. Reaching for a default is usually cleaner when you know what the fallback should be.
#void — Functions That Return Nothing
Not every function needs to return a value. A function that just prints to the console, saves data, or triggers an effect has a return type of void. Think of void as TypeScript's way of saying: "this function deliberately produces no result you should rely on."
function logScore(player: string, score: number): void {
console.log(`${player} scored ${score} points.`);
// no return statement needed
}
logScore("Alice", 4200);
logScore("Bob", 3100);#Typed Arrow Functions
Arrow functions follow the exact same annotation rules. You can write the types inline, or let TypeScript infer the return type from the function body — both approaches are common in real codebases.
// Explicit return type
const double = (n: number): number => n * 2;
// TypeScript infers the return type as number
const triple = (n: number) => n * 3;
// Arrow function stored in a typed variable
const greet: (name: string) => string = (name) => `Hi, ${name}!`;
console.log(double(5));
console.log(triple(5));
console.log(greet("Riya"));What does the ? symbol mean when placed after a function parameter name in TypeScript?
Let TypeScript infer return types when the body is simple
For short, obvious functions — a one-liner arrow, a simple transformation — you can omit the return type annotation and let TypeScript figure it out. Explicit return types shine on longer functions and public APIs, where the annotation serves as documentation and catches mistakes if the body ever changes.
Key takeaways
- Annotate parameters as name: type and return values as function(): ReturnType to make functions self-documenting and type-safe.
- Use ? for optional parameters (check for undefined inside the body) and = value for defaults (never undefined inside the body).
- Use void as the return type for functions that perform side effects and return nothing meaningful.
- Arrow functions follow the same annotation rules — types go on parameters, and the return type (if explicit) goes after the parameter list.
- TypeScript checks every call site against the function signature, catching wrong argument types before the code runs.
A default parameter supplies a fallback when the caller omits it. What does this code print?
function createMessage(text: string, prefix: string = "INFO"): string {
return `[${prefix}] ${text}`;
}
console.log(createMessage("Server started"));
console.log(createMessage("Disk full", "WARN"));This code has a bug — what's wrong?
function greetUser(name: string, title?: string): string {
return `Hello, ${title.toUpperCase()} ${name}!`;
}
greetUser("Turing");This function only prints — it returns no meaningful value. Fill in the parameter type for score and the return type that tells callers there is nothing to capture.
function logScore(player: string, score: ): { console.log(`${player} scored ${score} points.`); } logScore("Alice", 4200);
Arrange these lines to define a typed arrow function 'double' with an explicit number return type, then call it and log the result (10).
};
const double = (n: number): number => {return n * 2;
console.log(double(5));
Write a TypeScript function called formatPrice that takes a price (number) and an optional currency symbol (string). If no currency symbol is provided, use '$' as the default. The function should return a formatted string like '$9.99'. Then write a second arrow function called applyDiscount that takes a price and a discount percentage (both numbers) and returns the discounted price as a number. Finally, call both functions and log the results.
Try it live — edit the code and hit Run to see the output: