Functions and object shapes are the backbone of most TypeScript code. This chapter shows how to annotate them clearly.

Function Types

Annotate parameters and return types:

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

const multiply = (a: number, b: number): number => a * b;

function logMessage(msg: string): void {
    console.log(msg);  // void = no return value
}
  

Optional and Default Parameters

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

function buildUrl(path: string, query?: Record<string, string>): string {
    if (!query) return path;
    const params = new URLSearchParams(query);
    return `${path}?${params.toString()}`;
}

console.log(greet('Alice'));                    // "Hello, Alice!"
console.log(buildUrl('/api/users'));            // "/api/users"
console.log(buildUrl('/search', { q: 'ts' }));  // "/search?q=ts"
  

Function Type Expressions

Describe the shape of a function as a type:

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

const subtract: MathOp = (a, b) => a - b;
const divide: MathOp = (a, b) => a / b;

function apply(a: number, b: number, op: MathOp): number {
    return op(a, b);
}

console.log(apply(10, 4, subtract)); // 6
  

Interfaces

Interfaces define the shape of objects. They are extendable and work well for class contracts:

  interface User {
    id: number;
    name: string;
    email?: string;           // optional
    readonly createdAt: Date; // cannot be reassigned
}

function displayUser(user: User): void {
    console.log(`${user.name} (${user.id})`);
    // user.createdAt = new Date(); // Error: readonly
}

const alice: User = {
    id: 1,
    name: 'Alice',
    createdAt: new Date()
};
  

Extending Interfaces

  interface Person {
    name: string;
    age: number;
}

interface Employee extends Person {
    employeeId: string;
    department: string;
}

const dev: Employee = {
    name: 'Bob',
    age: 28,
    employeeId: 'E-100',
    department: 'Engineering'
};
  

Type Aliases

Type aliases can represent unions, primitives, or object shapes:

  type ID = string | number;
type Point = { x: number; y: number };
type Status = 'pending' | 'active' | 'archived';

function setStatus(id: ID, status: Status): void {
    console.log(`User ${id} is now ${status}`);
}
  

Interface vs Type Alias

Feature Interface Type Alias
Object shapes Yes Yes
Extend / merge Yes (extends, declaration merging) Limited
Unions / tuples No Yes
Primitives No Yes

Use interfaces for object contracts; use type aliases for unions, tuples, and utility compositions.

Index Signatures

When object keys are dynamic:

  interface StringMap {
    [key: string]: string;
}

const translations: StringMap = { hello: 'Hola', goodbye: 'Adiós' };
  

Typed functions and interfaces make APIs self-documenting and safe to refactor. Next, we explore classes and inheritance.