In the previous articles, we discussed why Object-Oriented Programming was introduced and explored different ways of creating objects using factory functions and classes.
Now it's time to look at one of the most important ideas behind OOP: Encapsulation.
Like every concept in this series, let's start with the problem rather than the definition.
The Real Problem Encapsulation Solves
Imagine you're building a bank account.
Without encapsulation:
class BankAccount {
balance = 1000;
}
const account = new BankAccount();
account.balance = -50000;
Now your account contains:
Balance = -50000
which may be impossible according to business rules.
The problem isn't that someone changed a variable.
The problem is:
Anybody can put the object into an invalid state.
Encapsulation is NOT About Hiding
Most beginners think:
Encapsulation = private fields
No.
Private fields are just one tool.
The actual goal is:
Protecting the integrity of an object's state.
An object should control how its data changes.
Why This Becomes Dangerous
In small applications, unrestricted access may not seem like a big deal.
As applications grow, however, data starts being accessed from many places.
Imagine:
- A payment module updating balances.
- A refund module updating balances.
- An admin panel updating balances.
- A reporting service reading balances.
Now suppose an issue appears.
A customer's balance becomes negative.
Where did it happen?
Which part of the application modified it?
Was validation skipped?
Did someone accidentally overwrite a value?
The more places that can directly manipulate data, the harder it becomes to reason about the system.
A Better Design
Instead of:
account.balance = -50000;
force all changes through methods:
class BankAccount {
private balance = 1000;
deposit(amount: number) {
this.balance += amount;
}
withdraw(amount: number) {
if (amount > this.balance) {
throw new Error('Insufficient funds');
}
this.balance -= amount;
}
getBalance() {
return this.balance;
}
}
Now:
account.withdraw(500);
is allowed.
But:
account.balance=-50000;
is impossible.
The object protects itself.
Think Like a Security Guard
Imagine a company database.
Bad design:
Employee Database
↑
Everybody can modify it
Good design:
Employee Database
↑
HR Department
↑
Employees submit requests
Employees don't directly change records.
They request changes.
The HR department validates them.
Encapsulation works exactly like this.
The Idea Behind Encapsulation
Encapsulation is about controlling access to an object's internal state.
Instead of allowing anyone to modify data directly, the object becomes responsible for managing its own data.
Rather than exposing the balance:
account.balance = 5000;
we expose behaviors:
account.deposit(5000);
or
account.withdraw(5000);
Now every change passes through rules defined by the object itself.
The object protects its own integrity.
This is the real purpose of Encapsulation.
Not hiding data.
Protecting data.
Encapsulation in TypeScript
TypeScript gives us access modifiers.
class User {
public name: string;
private password: string;
protected role: string;
}
public
Accessible everywhere.
user.name
works.
private
Accessible only inside the class.
user.password
❌ Error
protected
Accessible inside:
- current class
- derived classes
class User {
protected role = 'user';
}
class Admin extends User {
checkRole() {
console.log(this.role);
}
}
Works.
Important Reality About TypeScript
Many developers are surprised by this.
TypeScript:
private balance = 1000;
is primarily a compile-time restriction.
After compilation to JavaScript:
this.balance = 1000;
still exists.
TypeScript prevents you from accessing it in code, but it's not true runtime privacy.
Modern JavaScript introduced:
#balance
which is actual runtime privacy.
class Account {
#balance = 1000;
}
Now:
account.#balance
is impossible.
The Key Takeaway
Encapsulation is often described as hiding data.
A more useful way to think about it is this:
Encapsulation ensures that an object controls how its own state changes.
By doing so, it protects business rules, reduces accidental misuse, and makes software easier to maintain as systems grow.
What's Next?
Encapsulation helps us control access to data.
But another challenge still remains.
Even when objects manage their own state correctly, consumers often need to understand too many implementation details to use them.
In the next article, we'll explore Abstraction and see how hiding unnecessary complexity allows us to build systems that are easier to use and easier to change.

Top comments (0)