Skip to main content

Module 3: Functions in TypeScript

Functions are the building blocks of TypeScript applications. This module covers function types, parameters, return values, and advanced function patterns.


1. Function Type Annotations

Basic Function

function greet(name: string): string {
return `Hello, ${name}!`;
}

let result: string = greet("Alice");

Function with Multiple Parameters

function add(a: number, b: number): number {
return a + b;
}

console.log(add(5, 10)); // 15

Void Return Type

function logMessage(message: string): void {
console.log(message);
}

2. Optional Parameters

Use ? to make parameters optional.

function buildName(firstName: string, lastName?: string): string {
if (lastName) {
return `${firstName} ${lastName}`;
}
return firstName;
}

console.log(buildName("John")); // "John"
console.log(buildName("John", "Doe")); // "John Doe"
Parameter Order

Optional parameters must come after required parameters.


3. Default Parameters

function greet(name: string, greeting: string = "Hello"): string {
return `${greeting}, ${name}!`;
}

console.log(greet("Alice")); // "Hello, Alice!"
console.log(greet("Bob", "Hi")); // "Hi, Bob!"

Default Parameters with Type Inference

function createPoint(x: number = 0, y: number = 0) {
return { x, y };
}

4. Rest Parameters

Collect multiple arguments into an array.

function sum(...numbers: number[]): number {
return numbers.reduce((total, n) => total + n, 0);
}

console.log(sum(1, 2, 3)); // 6
console.log(sum(10, 20, 30, 40)); // 100

5. Function Expressions

Anonymous Function

let multiply = function(a: number, b: number): number {
return a * b;
};

Arrow Functions

let divide = (a: number, b: number): number => {
return a / b;
};

// Concise arrow function
let square = (n: number): number => n * n;

6. Function Types

Define the type of a function variable.

let mathOperation: (x: number, y: number) => number;

mathOperation = (a, b) => a + b; // ✅ OK
mathOperation = (a, b) => a * b; // ✅ OK
// mathOperation = (a: string) => a; // ❌ Error

Type Alias for Functions

type MathFunc = (a: number, b: number) => number;

let add: MathFunc = (x, y) => x + y;
let subtract: MathFunc = (x, y) => x - y;

7. Function Overloading

Define multiple function signatures.

// Overload signatures
function process(value: string): string;
function process(value: number): number;
function process(value: boolean): boolean;

// Implementation signature
function process(value: string | number | boolean): string | number | boolean {
if (typeof value === "string") {
return value.toUpperCase();
} else if (typeof value === "number") {
return value * 2;
} else {
return !value;
}
}

console.log(process("hello")); // "HELLO"
console.log(process(5)); // 10
console.log(process(true)); // false

8. Callback Functions

function fetchData(callback: (data: string) => void): void {
setTimeout(() => {
callback("Data loaded");
}, 1000);
}

fetchData((data) => {
console.log(data); // "Data loaded"
});

Callback with Error Handling

type Callback = (error: Error | null, data?: string) => void;

function loadUser(id: number, callback: Callback): void {
if (id > 0) {
callback(null, `User ${id}`);
} else {
callback(new Error("Invalid ID"));
}
}

9. Generic Functions

Create reusable functions that work with multiple types.

function identity<T>(value: T): T {
return value;
}

let num = identity<number>(42);
let str = identity<string>("Hello");
let auto = identity(100); // Type inferred as number

Generic Array Function

function getFirst<T>(arr: T[]): T | undefined {
return arr[0];
}

let firstNum = getFirst([1, 2, 3]); // number | undefined
let firstStr = getFirst(["a", "b", "c"]); // string | undefined

10. this in Functions

Regular Function Context

let user = {
name: "Alice",
greet: function() {
console.log(`Hello, ${this.name}`);
}
};

user.greet(); // "Hello, Alice"

Arrow Function and this

let timer = {
seconds: 0,
start: function() {
setInterval(() => {
this.seconds++;
console.log(this.seconds);
}, 1000);
}
};

timer.start(); // Correctly binds `this`

Explicit this Parameter

interface User {
name: string;
}

function greet(this: User, greeting: string) {
console.log(`${greeting}, ${this.name}`);
}

let user: User = { name: "Bob" };
greet.call(user, "Hello"); // "Hello, Bob"

Key Takeaways

✅ Always type function parameters and return values
✅ Use optional and default parameters for flexibility
Rest parameters collect variable arguments
Function overloading provides multiple signatures
Generics make functions reusable across types
✅ Arrow functions inherit this from surrounding scope


Practice Exercises

Exercise 1: Function with Optional Parameters

function calculateArea(width: number, height?: number): number {
return height ? width * height : width * width;
}

Exercise 2: Rest Parameters

function concatenate(...strings: string[]): string {
return strings.join(" ");
}

console.log(concatenate("Hello", "TypeScript", "World"));

Exercise 3: Generic Function

function reverseArray<T>(arr: T[]): T[] {
return arr.reverse();
}

console.log(reverseArray([1, 2, 3]));
console.log(reverseArray(["a", "b", "c"]));

Next Steps

In Module 4, we'll explore Interfaces and learn how to define contracts for objects, classes, and functions.