TypeScript: Functional or OOP — What to Choose in 2024?

Online Python Trainer for Beginners

Learn Python easily without overwhelming theory. Solve practical tasks with automatic checking, get hints in Russian, and write code directly in your browser — no installation required.

Start Course

Two Sides of the Same Coin: Functional and OOP Approaches in TypeScript

\n\n

The world of TypeScript is an amazing place where best practices from different worlds blend together. Have you ever wondered why some developers write code using classes and inheritance, while others use pure functions and composition? And most importantly: which approach will bring more benefit to your project?

\n\n

In this article, we won't argue which is better. We will break down functional programming versus object-oriented programming in TypeScript with real-world examples. You will learn when to use classes and when to use higher-order functions, and how to find the sweet spot in modern development.

\n\n

What is Functional Programming in TypeScript?

\n\n

Functional programming (FP) is a paradigm where the main building blocks are pure functions. They do not modify external state and always return the same result for the same input. TypeScript supports FP excellently thanks to its strong typing and capabilities for working with functions as data.

\n\n

Core Principles of FP in TypeScript

\n
    \n
  • Immutability — data is not changed, but created anew
  • \n
  • Pure functions — no side effects
  • \n
  • Composition — building complex behavior from simple functions
  • \n
  • Higher-order functions — functions that take or return other functions
  • \n
\n\n
// Example of pure functions and immutability in TypeScript\ntype User = {\n  readonly id: number;\n  readonly name: string;\n  readonly age: number;\n};\n\nconst addYear = (user: User): User => ({\n  ...user,\n  age: user.age + 1\n});\n\nconst users: User[] = [\n  { id: 1, name: 'Alice', age: 25 },\n  { id: 2, name: 'Bob', age: 30 }\n];\n\n// No mutations — creating a new array\nconst updatedUsers = users.map(addYear);\nconsole.log(users[0].age); // 25 (original unchanged)\nconsole.log(updatedUsers[0].age); // 26\n
\n\n

Notice readonly — this is a powerful TypeScript feature that helps enforce immutability at the type level.

\n\n

What is Object-Oriented Programming in TypeScript?

\n\n

OOP is built around objects that combine data and behavior. TypeScript adds classical inheritance, access modifiers, and interfaces to JavaScript, making OOP even more expressive.

\n\n

Core Principles of OOP in TypeScript

\n
    \n
  • Encapsulation — hiding internal state via private and protected
  • \n
  • Inheritance — creating class hierarchies
  • \n
  • Polymorphism — a single interface for different implementations
  • \n
  • Abstraction — working through interfaces, not concrete classes
  • \n
\n\n
// Example of OOP approach in TypeScript\nabstract class Animal {\n  constructor(protected name: string) {}\n\n  abstract makeSound(): string;\n\n  public introduce(): string {\n    return `I am ${this.name}, and I say ${this.makeSound()}`;\n  }\n}\n\nclass Dog extends Animal {\n  constructor(name: string) {\n    super(name);\n  }\n\n  public makeSound(): string {\n    return 'Woof!';\n  }\n}\n\nclass Cat extends Animal {\n  constructor(name: string) {\n    super(name);\n  }\n\n  public makeSound(): string {\n    return 'Meow!';\n  }\n}\n\nconst animals: Animal[] = [new Dog('Rex'), new Cat('Whiskers')];\nanimals.forEach(a => console.log(a.introduce()));\n// I am Rex, and I say Woof!\n// I am Whiskers, and I say Meow!\n
\n\n

Here, abstract and protected are TypeScript features not present in plain JavaScript. They allow building a strict architecture directly at the type level.

\n\n

Comparing Approaches: When to Use What?

\n\n

Let's break down a few

Blogs

Book Recommendations