TypeScript → Lesson 4: Functions

Lesson 4: Functions

Why functions exist, how to define and call them, parameter handling, returns, scope, and common patterns for clear, reusable code.

Learning goals

  • Explain why functions are useful (reuse, abstraction, clarity).
  • Know the difference between declarations, expressions, and arrow functions.
  • Use parameters and return values correctly.
  • Understand basic scope and guard clauses (early returns).
  • Name functions clearly and avoid common mistakes.

Why functions exist

Functions let you group a sequence of steps and give it a name. This makes code reusable, easier to read, and easier to test. Instead of copying the same code, you call a function whenever needed.

Function anatomy

Key parts: name, parameters, body, and return value.

// function declaration
  function greet(name) {
    return 'Hello ' + name;
  }

  // function expression
  const greet2 = function(name) {
    return 'Hi ' + name;
  };

  // arrow function (shorter syntax)
  const greet3 = (name) => `Hey ${name}`;

  console.log(greet('Ava')); // 'Hello Ava'

Parameters vs arguments

Parameters are the names in the function definition. Arguments are the actual values you pass when calling the function.

function add(a, b) { // a, b are parameters
  return a + b;
}

const result = add(2, 3); // 2 and 3 are arguments

Return value

Use return to send a value out of a function. If you omit return, the function returns undefined.

function noReturn() {
  const x = 1 + 2;
}
console.log(noReturn()); // undefined

// concise return
function withReturn() { return 42; }
console.log(withReturn()); // 42

Scope basics

Variables declared inside a function are local to that function. They are not visible outside. This prevents accidental conflicts between different parts of code.

function example() {
  const secret = 'shh'; // local
  return secret;
}

// secret is not defined here
// console.log(secret); // ReferenceError

Guard clauses & early return

Use early returns to handle invalid input and keep the main logic less nested.

function divide(a, b) {
  if (b === 0) return null; // guard clause
  return a / b;
}

Naming functions clearly

Choose names that describe what the function does (verb + noun). E.g. formatDate, calculateTotal, isAdult.

Common mistakes

  • Forgetting return when you need a value.
  • Using variables not defined in scope (ReferenceError).
  • Confusing calling vs referencing: fn() calls, fn references.
  • Mutating shared state inside functions — prefer pure functions when possible.

Examples

Double a number

function double(n) { return n * 2; }
console.log(double(4)); // 8

fullName from first & last

function fullName(first, last) {
  return first + ' ' + last;
}
console.log(fullName('Ava', 'Smith')); // 'Ava Smith'

clamp(value, min, max)

function clamp(value, min, max) {
  if (value < min) return min;
  if (value > max) return max;
  return value;
}
console.log(clamp(5, 1, 4)); // 4

isAdult(age)

function isAdult(age) {
  const n = Number(age);
  if (Number.isNaN(n)) return false;
  return n >= 18;
}
console.log(isAdult('20')); // true

Practice tasks

  1. Implement double(n) — returns 2*n.
  2. Implement fullName(first, last) — returns combined name.
  3. Implement clamp(value,min,max) — keep value within bounds.
  4. Implement isAdult(age) — returns true for 18+ (handle strings).

Summary checklist

  • Can define functions as declarations, expressions, and arrows.
  • Know parameters vs arguments and how return works.
  • Use guard clauses for early exits and avoid deep nesting.
  • Keep variables scoped and name functions clearly.
Programming Lesson 4
Programming → Lesson 4