Functions are fundamental in TypeScript. Learn how to type them properly.

Function Declarations

Basic Function

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

Function Parameters

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

// Optional parameters (use ?)
function greet(name: string, title?: string): string {
  if (title) {
    return `Hello, ${title} ${name}!`;
  }
  return `Hello, ${name}!`;
}

greet("Alice");              // "Hello, Alice!"
greet("Alice", "Dr.");       // "Hello, Dr. Alice!"

Default Parameters

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

greet("Alice");                    // "Hello, Alice!"
greet("Alice", "Hi");              // "Hi, Alice!"

Rest Parameters

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

sum(1, 2, 3);        // 6
sum(1, 2, 3, 4, 5);  // 15

Function Expressions

Named Function Expression

const multiply = function(x: number, y: number): number {
  return x * y;
};

Arrow Functions

// Single expression
const add = (a: number, b: number): number => a + b;

// Multiple statements
const greet = (name: string): string => {
  const message = `Hello, ${name}!`;
  return message;
};

Function Types

Type Annotations for Functions

// Function type
let myFunction: (a: number, b: number) => number;

myFunction = function(x: number, y: number): number {
  return x + y;
};

Type Aliases for Functions

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

const add: MathOperation = (a, b) => a + b;
const multiply: MathOperation = (a, b) => a * b;

Function Overloads

Define multiple function signatures for the same function.

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

// Implementation
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;
  }
}

process("hello");  // Returns: "HELLO"
process(5);        // Returns: 10
process(true);     // Returns: false

Return Types

Explicit Return Types

function getAge(): number {
  return 25;
}

function getName(): string {
  return "Alice";
}

void Return Type

For functions that don't return a value.

function logMessage(message: string): void {
  console.log(message);
  // No return statement needed
}

never Return Type

For functions that never return (throw errors or infinite loops).

function throwError(message: string): never {
  throw new Error(message);
}

function infiniteLoop(): never {
  while (true) {
    // Never returns
  }
}

this Parameter

Type the this context in functions.

interface User {
  name: string;
  greet(this: User): void;
}

const user: User = {
  name: "Alice",
  greet() {
    console.log(`Hello, I'm ${this.name}`);
  }
};

Generic Functions

Basic introduction (covered in detail in Intermediate level).

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

identity<string>("hello"); // string
identity<number>(42);        // number

Exercises

Exercise 1: Basic Functions

// Create a function called 'calculateArea' that:
// - Takes width (number) and height (number) as parameters
// - Returns the area (number)
// - Has proper type annotations

Exercise 2: Optional Parameters

// Create a function called 'createUser' that:
// - Takes name (string, required)
// - Takes email (string, optional)
// - Takes age (number, optional)
// - Returns a user object

Exercise 3: Default Parameters

// Create a function called 'createGreeting' that:
// - Takes name (string, required)
// - Takes greeting (string, default: "Hello")
// - Returns a greeting string

Exercise 4: Rest Parameters

// Create a function called 'average' that:
// - Takes any number of numbers as arguments
// - Returns the average (number)

Exercise 5: Function Overloads

// Create overloaded function 'format' that:
// - If given a string, returns it uppercase
// - If given a number, returns it as a string with 2 decimal places

Best Practices

  1. Always type function parameters - Never use implicit any
  2. Use explicit return types - Makes intent clear
  3. Prefer arrow functions - More concise for simple functions
  4. Use default parameters - Instead of optional parameters when possible
  5. Document complex functions - Add JSDoc comments

Common Mistakes

  1. Forgetting return type annotations
// ❌ Bad
function add(a: number, b: number) {
  return a + b;
}

// ✅ Good
function add(a: number, b: number): number {
  return a + b;
}
  1. Using any for parameters
// ❌ Bad
function process(data: any) {
  // ...
}

// ✅ Good
function process(data: UserData) {
  // ...
}
  1. Not handling optional parameters
// ❌ Bad
function greet(name: string, title?: string): string {
  return `Hello, ${title} ${name}!`; // title might be undefined
}

Next Steps

Learn about Interfaces.