Skip to main content

Encapsulation in TypeScript with NestJS, A Practical Guide 🤔

Encapsulation isn't just about hiding data or making it private. It's about bundling related data and behaviors into a single unit, and defining clear interfaces for interacting with that data.

One of the key principles of Object-Oriented Programming (OOP) is encapsulation. Encapsulation refers to the bundling of data and methods that operate on that data into a single unit, and controlling access to that data. This concept is fundamental to creating maintainable, scalable software.

Why NestJS?

NestJS is a framework for building efficient, scalable Node.js web applications. It uses modern JavaScript or TypeScript and combines elements of OOP ( Object-Oriented Programming), FP (Functional Programming), and FRP (Functional Reactive Programming). NestJS provides an out-of-the-box application architecture which allows developers to create highly testable, scalable, loosely coupled, and easily maintainable applications.

One of the best things about NestJS is that it makes full use of TypeScript's strong typing and advanced features like decorators. NestJS is built around the concept of modules, services, and controllers, all of which can encapsulate specific functionalities.

Encapsulation in NestJS

In NestJS, encapsulation is observed in how services and controllers are constructed and used. Services in NestJS are meant to encapsulate business logic, while controllers encapsulate request handling logic.

Encapsulation in Services

Services in NestJS are typically where your business logic lives. They encapsulate the methods and data they operate on. Here's an example of a service that manages users

import { Injectable } from "@nestjs/common";

export class UsersService {
private readonly users: Array<{ id: number; name: string }> = [
{ id: 1, name: "John Doe" },

findAll(): Array<{ id: number; name: string }> {
return this.users;

findOne(id: number): { id: number; name: string } | undefined {
return this.users.find((user) => === id);

In the UsersService, we're encapsulating the data (users array) and the methods that operate on that data (findAll, findOne). This service doesn't know anything about HTTP or databases; it's just concerned with managing users. The data (in this case, the users array) is kept private and can only be accessed and manipulated through the methods provided by the service. This is encapsulation in action.

TypeScript Course Instructor Image
TypeScript Course Instructor Image

Time To Transition From JavaScript To TypeScript

Level Up Your TypeScript And Object Oriented Programming Skills. The only complete TypeScript course on the marketplace you building TypeScript apps like a PRO.


Encapsulation in Controllers

Controllers in NestJS handle incoming HTTP requests and return responses. They encapsulate request handling logic. Here's an example of a controller that manages HTTP requests for users:

import { Controller, Get, Param } from "@nestjs/common";
import { UsersService } from "./users.service";

export class UsersController {
constructor(private usersService: UsersService) {}

findAll(): Array<{ id: number; name: string }> {
return this.usersService.findAll();

findOne(@Param("id") id: string): { id: number; name: string } | undefined {
return this.usersService.findOne(+id);

In the UsersController, we're encapsulating the HTTP request handling logic. The findAll method handles GET requests to the '/users' URL, and the findOne method handles GET requests to the '/users/:id' URL. This controller doesn't know anything about the data or how it's stored; it's just concerned with handling HTTP requests and responses.

Why Use Encapsulation?

  1. Data Hiding: Encapsulation hides the internal state of an object, making it inaccessible to the outside world. This prevents unauthorized access and potential misuse.

  2. Improved Maintainability: Encapsulation makes software easier to maintain. Changes to one part of the system won't impact other parts if the data is properly encapsulated.

  3. Flexibility and Extensibility: With encapsulation, you can easily extend and modify behaviors and states without affecting other parts of the code.

  4. Modular Code: Encapsulation promotes modular code, where each object is responsible for specific tasks. This aids in understanding, testing, and reusing code.

  5. Control over Data: Encapsulation provides control over data validation and integrity by using getter and setter methods.

What Can You Do Next 🙏😊

If you liked the article, consider subscribing to Cloudaffle, my YouTube Channel, where I keep posting in-depth tutorials and all edutainment stuff for software developers.

YouTube @cloudaffle