Back to Interview PrepGet interview ready with AILearn each topic the way interviewers ask it, then answer like you would in the interview.
Course progress0/12 chapters · 0%

Chapter 4 of 13

~14 min

Functions & Type Annotations

Typing a function means describing both what it accepts and what it returns, which lets the compiler catch a wrong argument or a misused result at every call site, not just inside the function body itself.

Typing Parameters and Return Values

Each parameter gets its own annotation, and the return type is written after the parameter list. TypeScript can usually infer the return type from the function body, but writing it explicitly on exported or public functions is good practice: it documents intent and prevents an accidental change inside the function from silently widening its return type for every caller.

Try it yourself

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

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

console.log(add(2, 3));      // 5
console.log(multiply(2, 3)); // 6
Console

No output yet. Use console.log() to print values here.

Optional and Default Parameters

A parameter suffixed with `?`, like `discount?: number`, is optional - callers may omit it, and inside the function its type includes `undefined`. A default parameter, written `discount: number = 0`, is also optional to callers, but instead of becoming `undefined` when omitted, it falls back to the given default value, and its type does not need to include `undefined` at all.

Optional and default parameters must come after all required parameters in the parameter list - TypeScript (matching JavaScript) does not support required parameters after optional ones.

Try it yourself

function createUser(name: string, age?: number): string {
  return age !== undefined ? `${name} (${age})` : name;
}

function applyDiscount(price: number, percent: number = 10): number {
  return price - (price * percent) / 100;
}

console.log(createUser('Ada'));         // 'Ada'
console.log(createUser('Ada', 37));     // 'Ada (37)'
console.log(applyDiscount(100));        // 90 - uses the default of 10
console.log(applyDiscount(100, 25));    // 75
Console

No output yet. Use console.log() to print values here.

Function Overloads

Function overloads let a single function name accept several distinct call signatures, where the relationship between a specific input type and output type could not be expressed with a single signature using unions alone. You write several overload signatures followed by one general implementation signature that is compatible with all of them - only the overload signatures are visible to callers, and the implementation signature itself is not directly callable from outside.

Try it yourself

function parseValue(value: string): string[];
function parseValue(value: number): number;
function parseValue(value: string | number): string[] | number {
  if (typeof value === 'string') {
    return value.split(',');
  }
  return value * 2;
}

const parts = parseValue('a,b,c'); // typed as string[]
const doubled = parseValue(21);    // typed as number
Console

No output yet. Use console.log() to print values here.

Typing Arrow Functions and Callbacks

An arrow function's type can be written as a standalone type alias, such as `type Comparator = (a: number, b: number) => number`, which is especially useful for describing a callback parameter accepted by another function (like a custom `sort` helper). This keeps the shape of the expected callback explicit and reusable, rather than repeating an inline function type at every call site.

Try it yourself

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

function customSort(items: number[], compare: Comparator): number[] {
  return [...items].sort(compare);
}

const ascending: Comparator = (a, b) => a - b;
console.log(customSort([3, 1, 2], ascending)); // [1, 2, 3]
Console

No output yet. Use console.log() to print values here.

Coding challenge

Write a function formatName(first: string, last: string, middle?: string): string that joins the parts with spaces, only including the middle name if it was provided. Call it twice, with and without a middle name.

// Write your solution here

Console

No output yet. Use console.log() to print values here.

Answer every question below to mark this chapter as complete.

Quiz Yourself

Score: 0/5

1. Why is it good practice to explicitly annotate the return type of an exported function, even though TypeScript could infer it?

2. How does a default parameter (`percent: number = 10`) differ from an optional parameter (`percent?: number`) from inside the function body?

3. In a function with several overload signatures, which signature is directly callable from outside the function?

4. What ordering rule applies to optional and default parameters relative to required ones?

5. What is the benefit of writing a standalone type alias like `type Comparator = (a: number, b: number) => number` for a callback parameter?

You're viewing a free lesson. Sign up free to track your progress and unlock the full course.Sign up freeSign in