02 - Functions

📋 Jump to Takeaways

Basic Function Syntax

Type the parameters and the return value:

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

// Arrow function — same thing
const multiply = (a: number, b: number): number => a * b;

The return type is often inferred — you can omit it if it's obvious:

function add(a: number, b: number) {  // return type inferred as number
  return a + b;
}

void and never

// void — function doesn't return anything
function log(message: string): void {
  console.log(message);
}

// never — function never completes (throws or infinite loop)
function throwError(message: string): never {
  throw new Error(message);
}

Optional and Default Parameters

// Optional — might not be passed (becomes undefined)
function greet(name: string, greeting?: string): string {
  return `${greeting || "Hello"}, ${name}`;
}

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

// Default — uses a fallback value if not passed
function createUser(name: string, age: number = 18) {
  return { name, age };
}

createUser("Bob");        // { name: "Bob", age: 18 }
createUser("Bob", 25);    // { name: "Bob", age: 25 }

Rest Parameters

Collect any number of arguments into an array:

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

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

Function Types

Define the shape of a function — useful for callbacks:

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

const divide: MathOperation = (a, b) => a / b;  // types inferred from MathOperation

Callback Types

When a function takes another function as a parameter:

function fetchData(url: string, callback: (data: string) => void): void {
  // ... fetch data
  callback("result");
}

// Or define the callback type separately
type OnComplete = (success: boolean) => void;

function save(data: string, onComplete: OnComplete): void {
  // ... save data
  onComplete(true);
}

Overloads

Same function name, different parameter types. Use overloads when the return type depends on the input type — if the return type is always the same, a union parameter is simpler:

// Union parameter is enough when return type doesn't change
function log(value: string | number): void {
  console.log(value);
}

// Overloads are useful when return type depends on input type
function format(value: string): string;
function format(value: number): string;
function format(value: string | number): string {
  if (typeof value === "string") {
    return value.toUpperCase();
  }
  return value.toFixed(2);
}

format("hello");  // "HELLO"
format(3.14159);  // "3.14"

Overloads also work with different return types based on input:

function parse(input: string): string[];
function parse(input: string[]): string;
function parse(input: string | string[]): string | string[] {
  if (typeof input === "string") {
    return input.split(",");    // string in → string[] out
  }
  return input.join(",");       // string[] in → string out
}

parse("a,b,c");        // string[]
parse(["a", "b", "c"]); // string

The implementation signature must be compatible with all overload signatures.

⚠️ Important: All overload signatures must appear directly above the implementation with no other code in between.

Key Takeaways

  • Type parameters and return values
  • ? makes a parameter optional, = value gives it a default
  • void = returns nothing, never = never returns
  • Use function types (type Fn = (a: number) => string) for callbacks
  • Let TypeScript infer return types when obvious
  • Rest parameters (...numbers: number[]) accept any number of arguments as a typed array
  • Overloads let you define multiple signatures when the return type depends on the input type
  • Inline callback typing: callback: (data: string) => void directly in parameters

📝 Ready to test your knowledge?

Answer the quiz below to mark this lesson complete.

© 2026 ByteLearn.dev. Free courses for developers. · Privacy