TypeScript course menu
Typing Functions in TypeScript: Parameters, Return Types, Optional and Default Parameters
Learn how to type functions in TypeScript: parameter and return type annotations, optional parameters with ?, default values, rest parameters, arrow functions, void, typing callbacks, and destructured object parameters.
On this page
Functions are where types help most: they define the contract between the code that calls a function and the code inside it.
Parameters and return types#
function applyDiscount(price: number, percent: number): number {
return price - (price * percent) / 100;
}
const finalPrice = applyDiscount(1200, 15);
console.log(finalPrice);1020- Every parameter needs a type:
price: number. - The return type goes after the parentheses:
): number. It is usually inferred, but writing it on important functions documents the intent and catches mistakes inside the function:
function isAdult(age: number): boolean {
if (age >= 18) {
return "yes";
}
return false;
}error TS2322: Type 'string' is not assignable to type 'boolean'.Callers must pass the right number and types of arguments, so applyDiscount(1200) and applyDiscount("1200", 15) are both errors.
Optional parameters#
A ? after a parameter name makes it optional. Inside the function, its type includes undefined:
function greet(name: string, title?: string): string {
return title ? `Hello, ${title} ${name}` : `Hello, ${name}`;
}
console.log(greet("Rao"));
console.log(greet("Rao", "Dr."));Hello, Rao
Hello, Dr. RaoOptional parameters must come after required ones.
Default values#
A default value makes the parameter optional, and its type is inferred from the default:
function formatPrice(amount: number, currency = "₹", decimals = 2): string {
return `${currency}${amount.toFixed(decimals)}`;
}
console.log(formatPrice(499));
console.log(formatPrice(12.5, "$"));
console.log(formatPrice(499, "₹", 0));₹499.00
$12.50
₹499Rest parameters#
A rest parameter collects extra arguments into an array, typed as an array:
function sum(...numbers: number[]): number {
return numbers.reduce((total, n) => total + n, 0);
}
console.log(sum(), sum(5), sum(1, 2, 3, 4));0 5 10Arrow functions#
Annotations work the same way on arrow functions:
const square = (n: number): number => n * n;
const isEven = (n: number) => n % 2 === 0; // return type inferred as boolean
console.log(square(7), isEven(7));49 falsevoid#
void means a function does not return a useful value:
function log(message: string): void {
console.log(`[log] ${message}`);
}
log("Server started");[log] Server startedFunctions as parameters#
To accept a callback, describe its type with arrow syntax: (parameters) => returnType:
function repeat(times: number, action: (i: number) => void): void {
for (let i = 1; i <= times; i++) action(i);
}
repeat(3, (i) => console.log(`Step ${i}`));Step 1
Step 2
Step 3The callback's parameter i did not need an annotation: TypeScript knew it from action's type (contextual typing). Function types are covered further in Function Types and Overloads.
Object parameters#
For functions with several options, take one object and destructure it. The type goes after the whole pattern:
function createUser({ name, age, isAdmin = false }: { name: string; age: number; isAdmin?: boolean }) {
return `${name} (${age})${isAdmin ? " [admin]" : ""}`;
}
console.log(createUser({ name: "Asha", age: 30 }));
console.log(createUser({ name: "Ravi", age: 25, isAdmin: true }));Asha (30)
Ravi (25) [admin]That inline type is getting long; giving it a name with an interface or type alias is cleaner. A common mistake is writing { name: string } inside the destructuring pattern itself, which renames the property instead of typing it.
Practice#
Practice exercise
Write calculateEmi(principal: number, annualRatePercent: number, months = 12): number that returns the monthly loan instalment using P * r * (1 + r)^n / ((1 + r)^n - 1), where r is the monthly rate as a decimal. Print the EMI for ₹1,00,000 at 12% a year for 12 months and for 24 months, rounded to whole rupees.
Show solution
function calculateEmi(principal: number, annualRatePercent: number, months = 12): number {
const r = annualRatePercent / 12 / 100;
const factor = (1 + r) ** months;
return (principal * r * factor) / (factor - 1);
}
console.log(Math.round(calculateEmi(100000, 12)));
console.log(Math.round(calculateEmi(100000, 12, 24)));8885
4707Key takeaway#
Finished this lesson?