Functions and Type Annotations
Functions are a core part of both JavaScript and TypeScript. Type annotations can be used with function parameters and return types to add type safety.
Types with function parameters
We have briefly covered using types with function parameters, the syntax looks like this:
function createPizza(name: string): string {
return `Created pizza: ${name}`;
}
The name parameter is typed as string, and the function returns a string.
Function return types
You can specify what type a function returns:
function calculateTotal(price: number, quantity: number): number {
return price * quantity;
}
The : number after the parentheses (()) means this function returns a type of number.
Multiple parameters
Functions can have multiple parameters, each with it's own type:
function createPizzaOrder(pizzaName: string, quantity: number, price: number): string {
return `Order: ${quantity}x ${pizzaName} - Total: $${(quantity * price).toFixed(2)}`;
}
Optional parameters
You can make parameters optional using the ? operator. This example requires a pizza to be passed to the function, but has optional toppings:
Loading code...
function addTopping(pizza: string, topping?: string): string {
if (topping) {
return `${pizza} with ${topping}`;
}
return pizza;
}
console.log(addTopping("Margherita")); // Margherita
console.log(addTopping("Margherita", "pepperoni")); // Margherita with pepperoni
Default parameters
Parameters can have default values provided. These values are used if no value if provided. This example sets the pizza size to be medium unless an overriding value is passed:
Loading code...
function createPizza(name: string, size: string = "medium"): string {
return `${size} ${name}`;
}
console.log(createPizza("Margherita")); // "medium Margherita"
console.log(createPizza("Margherita", "large")); // "large Margherita"
TypeScript can infer the type from the default value, but it's good practice to be explicit:
function calculateTotal(price: number, tax: number = 0.1): number {
return price * (1 + tax);
}
Rest parameters
You can use rest parameters to accept a variable number of arguments:
Loading code...
function addToppings(...toppings: string[]): string {
return toppings.join(", ");
}
console.log(addToppings("pepperoni", "peppers"));
console.log(addToppings("pepperoni", "mushrooms", "olives", "peppers"));
Arrow functions
Arrow functions use type annotations in the same way:
Loading code...
const greet = (name: string): string => {
return `Hello, ${name}!`;
};
const add = (a: number, b: number): number => a + b;
console.log(greet('Maggie'));
console.log(add(5, 10));
Function overloads
TypeScript supports function overloads (multiple function signatures):
Loading code...
function process(value: string): string;
function process(value: number): number;
function process(value: string | number): string | number {
if (typeof value === "string") {
return value.toUpperCase();
}
return value * 2;
}
console.log(process("typescript")); // TYPESCRIPT
console.log(process(7)); // 14
console.log(process(7, "typescript")); // Expected 1 arguments, but got 2.
The error "Expected 1 arguments, but got 2." is beause all functions are set to receive 1 argument.
Functions as parameters
Functions that are passed as parameters can also be typed:
Loading code...
function calculate(a: number, b: number, operation: (x: number, y: number) => number): number {
return operation(a, b);
}
const add = (x: number, y: number): number => x + y;
const multiply = (x: number, y: number): number => x * y;
console.log(calculate(5, 3, add)); // 8
console.log(calculate(5, 3, multiply)); // 15
Functions as return values
You can also type functions that are returned:
Loading code...
function multiply(factor: number): (value: number) => number {
return (value: number) => value * factor;
}
const double = multiply(2);
console.log(double(10)); // 20
Functions with type annotations are ideal for building type-safe applications. Previously, we have briefly looked at union types, and we will cover these in more detail next.