Core Concepts
Pure Functions
Section titled “Pure Functions”Functions that always return the same output for the same input and have no side effects.
Characteristics
Section titled “Characteristics”- Deterministic - Same input always produces same output
- No Side Effects - Doesn’t modify external state
- No Dependencies - Doesn’t depend on external mutable state
Examples
Section titled “Examples”// Pure function - deterministic and no side effectsfunction add(a: number, b: number): number { return a + b;}
function multiply(a: number, b: number): number { return a * b;}
// Impure - relies on external statelet count = 0;function incrementCount(): number { return ++count; // Side effect: modifies external state}
// Impure - non-deterministicfunction getCurrentTime(): Date { return new Date(); // Returns different value each call}
// Impure - has side effectfunction logAndAdd(a: number, b: number): number { console.log('Adding numbers'); // Side effect: I/O return a + b;}
// Pure version - inject dependenciesfunction formatTime(date: Date): string { return date.toISOString();}Benefits of Pure Functions
Section titled “Benefits of Pure Functions”✅ Easy to test - no setup required ✅ Easy to reason about - no hidden behavior ✅ Cacheable - memoization possible ✅ Parallelizable - no race conditions ✅ Composable - can be combined safely
Immutability
Section titled “Immutability”Data that cannot be changed after creation. Instead of modifying data, create new data.
Array Operations
Section titled “Array Operations”const numbers = [1, 2, 3];
// Bad - mutates original arraynumbers.push(4);numbers.sort();numbers.splice(1, 1);
// Good - creates new arraysconst withFour = [...numbers, 4];const sorted = [...numbers].sort();const withoutSecond = numbers.filter((_, i) => i !== 1);Object Updates
Section titled “Object Updates”const user = { name: 'John', age: 30 };
// Bad - mutates objectuser.age = 31;user.email = 'john@example.com';
// Good - creates new objectconst updatedUser = { ...user, age: 31 };const withEmail = { ...user, email: 'john@example.com' };Nested Updates
Section titled “Nested Updates”const state = { user: { profile: { name: 'John', email: 'john@example.com' }, settings: { theme: 'dark' } }};
// Bad - mutates nested objectstate.user.profile.email = 'newemail@example.com';
// Good - immutable deep updateconst newState = { ...state, user: { ...state.user, profile: { ...state.user.profile, email: 'newemail@example.com' } }};Array of Objects
Section titled “Array of Objects”const users = [ { id: 1, name: 'John', active: true }, { id: 2, name: 'Jane', active: false }];
// Update single user immutablyconst updatedUsers = users.map(user => user.id === 1 ? { ...user, active: false } : user);
// Add new userconst withNewUser = [...users, { id: 3, name: 'Bob', active: true }];
// Remove userconst withoutUser = users.filter(user => user.id !== 2);First-Class Functions
Section titled “First-Class Functions”Functions as values that can be assigned to variables, passed as arguments, and returned from other functions.
Functions as Values
Section titled “Functions as Values”// Assign function to variableconst greet = (name: string): string => `Hello, ${name}!`;
// Store functions in data structuresconst operations = { add: (a: number, b: number) => a + b, subtract: (a: number, b: number) => a - b, multiply: (a: number, b: number) => a * b};
operations.add(5, 3); // 8Functions as Arguments
Section titled “Functions as Arguments”function executeOperation( a: number, b: number, operation: (x: number, y: number) => number): number { return operation(a, b);}
const sum = executeOperation(5, 3, (a, b) => a + b); // 8const product = executeOperation(5, 3, (a, b) => a * b); // 15
// Array methods accept functionsconst numbers = [1, 2, 3, 4, 5];const doubled = numbers.map(n => n * 2);const evens = numbers.filter(n => n % 2 === 0);Functions Returning Functions
Section titled “Functions Returning Functions”function createMultiplier(factor: number) { return (value: number): number => value * factor;}
const double = createMultiplier(2);const triple = createMultiplier(3);
double(5); // 10triple(5); // 15
// Creating validatorsfunction createValidator(min: number, max: number) { return (value: number): boolean => value >= min && value <= max;}
const isValidAge = createValidator(0, 120);const isValidPercentage = createValidator(0, 100);
isValidAge(25); // trueisValidPercentage(150); // falseHigher-Order Functions
Section titled “Higher-Order Functions”Functions that take functions as arguments or return functions as results.
Transform each element in a collection:
const numbers = [1, 2, 3, 4, 5];
// Double each numberconst doubled = numbers.map(n => n * 2);// [2, 4, 6, 8, 10]
// Convert to objectsconst users = ['John', 'Jane', 'Bob'].map((name, id) => ({ id, name}));// [{ id: 0, name: 'John' }, ...]Filter
Section titled “Filter”Select elements that match a condition:
const numbers = [1, 2, 3, 4, 5];
// Get even numbersconst evens = numbers.filter(n => n % 2 === 0);// [2, 4]
// Get numbers greater than 3const greaterThanThree = numbers.filter(n => n > 3);// [4, 5]
// Filter objectsconst users = [ { name: 'John', active: true }, { name: 'Jane', active: false }];
const activeUsers = users.filter(user => user.active);// [{ name: 'John', active: true }]Reduce
Section titled “Reduce”Accumulate values into a single result:
const numbers = [1, 2, 3, 4, 5];
// Sumconst sum = numbers.reduce((acc, n) => acc + n, 0);// 15
// Productconst product = numbers.reduce((acc, n) => acc * n, 1);// 120
// Group by propertyconst users = [ { name: 'John', role: 'admin' }, { name: 'Jane', role: 'user' }, { name: 'Bob', role: 'admin' }];
const byRole = users.reduce((acc, user) => { const role = user.role; return { ...acc, [role]: [...(acc[role] || []), user] };}, {} as Record<string, typeof users>);// { admin: [...], user: [...] }Combining Operations
Section titled “Combining Operations”const numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
const result = numbers .filter(n => n % 2 === 0) // Get even numbers .map(n => n * 2) // Double them .reduce((acc, n) => acc + n, 0); // Sum them// 60
// Real-world exampleconst orders = [ { id: 1, amount: 100, status: 'paid' }, { id: 2, amount: 200, status: 'pending' }, { id: 3, amount: 150, status: 'paid' }];
const totalPaid = orders .filter(order => order.status === 'paid') .map(order => order.amount) .reduce((sum, amount) => sum + amount, 0);// 250Best Practices
Section titled “Best Practices”✅ Write pure functions whenever possible ✅ Use immutable data structures ✅ Compose small, focused functions ✅ Avoid side effects ✅ Use higher-order functions ✅ Keep functions deterministic ✅ Make dependencies explicit ✅ Return new data instead of mutating
Don’ts
Section titled “Don’ts”❌ Mutate function arguments
❌ Depend on external mutable state
❌ Use global variables
❌ Have hidden side effects
❌ Mix pure and impure logic
❌ Modify objects in place
❌ Use void functions (prefer returns)