<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:cc="http://cyber.law.harvard.edu/rss/creativeCommonsRssModule.html">
    <channel>
        <title><![CDATA[Stories by Maria Jahan Chowdhury on Medium]]></title>
        <description><![CDATA[Stories by Maria Jahan Chowdhury on Medium]]></description>
        <link>https://medium.com/@mariachowdhry?source=rss-7646f0d470a5------2</link>
        <image>
            <url>https://cdn-images-1.medium.com/fit/c/150/150/1*VKdIbmh-zJQV1KEMoMhoxw.jpeg</url>
            <title>Stories by Maria Jahan Chowdhury on Medium</title>
            <link>https://medium.com/@mariachowdhry?source=rss-7646f0d470a5------2</link>
        </image>
        <generator>Medium</generator>
        <lastBuildDate>Sat, 30 May 2026 07:54:59 GMT</lastBuildDate>
        <atom:link href="https://medium.com/@mariachowdhry/feed" rel="self" type="application/rss+xml"/>
        <webMaster><![CDATA[yourfriends@medium.com]]></webMaster>
        <atom:link href="http://medium.superfeedr.com" rel="hub"/>
        <item>
            <title><![CDATA[The Four Pillars of OOP in TypeScript: Building Scalable and Maintainable Applications]]></title>
            <link>https://medium.com/@mariachowdhry/the-four-pillars-of-oop-in-typescript-building-scalable-and-maintainable-applications-762841eb8dba?source=rss-7646f0d470a5------2</link>
            <guid isPermaLink="false">https://medium.com/p/762841eb8dba</guid>
            <category><![CDATA[oop]]></category>
            <category><![CDATA[programming]]></category>
            <category><![CDATA[abstract]]></category>
            <category><![CDATA[typescript]]></category>
            <category><![CDATA[web-development]]></category>
            <dc:creator><![CDATA[Maria Jahan Chowdhury]]></dc:creator>
            <pubDate>Wed, 27 May 2026 11:18:57 GMT</pubDate>
            <atom:updated>2026-05-27T11:18:57.321Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*zbqxLoAykDeaDMUinI9N-A.png" /></figure><h3>Introduction</h3><p>In large-scale software development, managing complexity is the ultimate challenge. As a codebase grows, tightly coupled logic and repetitive patterns can turn a project into an unmaintainable “spaghetti code” nightmare.</p><p>Object-Oriented Programming (OOP) addresses this challenge by providing a structured framework to model real-world entities. In this technical deep dive, we will explore how the four core pillars of OOP — Inheritance, Polymorphism, Abstraction, and Encapsulation — leverage TypeScript’s robust type system to help you write scalable, organized, and enterprise-ready applications.</p><h3>1. Inheritance: Reusing Code and Establishing Hierarchy</h3><p>Inheritance allows a new class (subclass or child class) to inherit properties and behaviors (methods) from an existing class (superclass or parent class). This establishes a clear structural hierarchy and prevents code duplication across similar entities.</p><p>TypeScript Implementation Below is a practical example where a Student class inherits common traits from a base Person class using the extends keyword and invokes the parent setup using super():</p><pre>// Superclass (Parent Class)<br>class Person {<br>  name: string;<br>  age: number;<br>  address: string;</pre><pre>  constructor(name: string, age: number, address: string) {<br>    this.name = name;<br>    this.age = age;<br>    this.address = address;<br>  }</pre><pre>  getSleep(numOfHours: number): void {<br>    console.log(`${this.name} sleeps for ${numOfHours} hours.`);<br>  }<br>}</pre><pre>// Subclass (Child Class) inheriting from Person<br>class Student extends Person {<br>  rollNo: number;</pre><pre>  constructor(name: string, age: number, address: string, rollNo: number) {<br>    // Calling the constructor of the Parent class using super()<br>    super(name, age, address); <br>    this.rollNo = rollNo;<br>  }<br>}</pre><pre>// Creating an instance of the Student class<br>const student1 = new Student(&quot;Vijay&quot;, 18, &quot;Bangladesh&quot;, 1981);</pre><pre>// Accessing a method inherited from the Parent class<br>student1.getSleep(10); <br>// Output: Vijay sleeps for 10 hours.</pre><h3>How it Reduces Complexity</h3><p>Eliminates Code Redundancy (DRY Principle): Instead of rewriting name, age, and common behaviors like getSleep for Student, Teacher, or Employee modules, code is written and tested once in the Person class. Centralized Maintenance: If you need to modify how a personal profile handles basic data updates later on, modifying the parent class updates all child classes instantly.</p><h3>2. Polymorphism: The Power of Many Forms</h3><p>Polymorphism means “many forms.” It allows different classes to be treated as instances of the same superclass or interface, while enabling each class to implement its own specific behavior via method overriding.</p><p>TypeScript Implementation Here, a subclass overrides an inherited method to change its specific execution details while maintaining the exact same functional signature:</p><pre>class NormalPerson {<br>  getSleep(): void {<br>    console.log(&quot;I am a Normal Happy Person. I sleep for 8 hours.&quot;);<br>  }<br>}</pre><pre>class NextLevelDeveloper extends NormalPerson {<br>  // Overriding the parent method to fit a developer&#39;s reality<br>  getSleep(): void {<br>    console.log(&quot;I am a Next Level developer. I sleep for 6 hours.&quot;);<br>  }<br>}</pre><pre>// Processing polymorphic entities<br>const people: NormalPerson[] = [new NormalPerson(), new NextLevelDeveloper()];</pre><pre>people.forEach((person) =&gt; {<br>  person.getSleep(); <br>  // Automatically runs the correct implementation depending on the actual instance type!<br>});</pre><h3>How it Reduces Complexity</h3><p>Removes Messy Conditional Blocks: Without polymorphism, you would need complex if/else or switch statements checking system types to determine how a specific user should sleep or execute actions.</p><p>Pluggable Architecture: You can introduce entirely new types of entities to your array down the road, and as long as they inherit from the base class, the consumption logic remains totally unchanged.</p><h3>3. Abstraction: Hiding Complexity Behind Simple Interfaces</h3><p>Abstraction means hiding complex implementation details and showing only the essential features to the user. This establishes a “contract” of what an object can do, without forcing the surrounding application to know exactly how it does it under the hood. In TypeScript, abstraction is primarily achieved using Interfaces and Abstract Classes.</p><p>TypeScript Implementation An abstract class serves as a blueprint that cannot be directly instantiated itself, forcing concrete subclasses to implement its declared methods:</p><pre>// Blueprint setup: Declares intent, but cannot be directly instantiated<br>abstract class MediaPlayer {<br>  abstract play(): void;<br>  abstract pause(): void;<br>  abstract stop(): void;<br>}</pre><pre>// Concrete implementation executing the hidden details<br>class CustomMediaPlayer extends MediaPlayer {<br>  play(): void {<br>    console.log(&quot;Playing music track...&quot;);<br>  }<br>  pause(): void {<br>    console.log(&quot;Music track is paused!&quot;);<br>  }<br>  stop(): void {<br>    console.log(&quot;Music track is stopped!&quot;);<br>  }<br>}</pre><pre>const myPlayer = new CustomMediaPlayer();<br>myPlayer.play(); // Output: Playing music track...</pre><h3>How it Reduces Complexity</h3><p>Minimizes Cognitive Load: Developers calling your player service only care about running .play() or .stop(). They do not need to process audio buffering strategies or device driver details. Decouples System Layers: The high-level application modules depend strictly on the abstract blueprint. This makes it trivial to swap out entire underlying implementations (e.g., changing audio libraries) without breaking dependent application components.</p><h3>4. Encapsulation: Shielding Internal State</h3><p>Encapsulation is the practice of bundling data (properties) and methods that operate on that data into a single unit (a class), while strictly hiding the internal state from unauthorized modifications by external code blocks. TypeScript manages this beautifully using access modifiers: public, protected, and private.</p><p>TypeScript Implementation By setting internal fields to private, we protect the integrity of the data and route modifications safely through controlled gateways:</p><pre>class BankAccount {<br>  public userName: string;<br>  private _userBalance: number; // &#39;private&#39; locks this variable from the outside world</pre><pre> constructor(userName: string, initialBalance: number) {<br>    this.userName = userName;<br>    this._userBalance = initialBalance;<br>  }</pre><pre>  // Safe way to view the balance<br>  public getBalance(): number {<br>    return this._userBalance;<br>  }</pre><pre>  // Safe way to change the balance with rules<br>  public deposit(amount: number): void {<br>    if (amount &gt; 0) {<br>      this._userBalance += amount;<br>      console.log(`Deposited: ${amount} USD`);<br>    } else {<br>      console.log(&quot;Invalid amount!&quot;);<br>    }<br>  }<br>}</pre><pre>const myAccount = new BankAccount(&quot;Vijay Thalapathi&quot;, 20);</pre><pre>// myAccount._userBalance = 999999; // ❌ ERROR! TypeScript won&#39;t let you touch this directly.<br>myAccount.deposit(500);            // ✅ SUCCESS! Safe and controlled.</pre><h3>How it Reduces Complexity</h3><p>Prevents Unintended Side Effects: Restricting variables ensures that an outside process can’t randomly change data variables inside an object, preventing strange, hard-to-trace bugs.</p><p>Single Source of Truth: All validation rules, error handling, and formatting constraints are safely locked inside the class. If a variable’s value ends up corrupted, you only have one single location to look into for debugging.</p><h3>Conclusion</h3><p>As your TypeScript applications scale, mastering the four pillars of OOP becomes essential for managing codebase complexity. Encapsulation safeguards internal states from unexpected side effects, while abstraction reduces cognitive load by exposing only necessary interfaces. Concurrently, inheritance eliminates code redundancy, and polymorphism enables dynamic, conditional-free behavior. By structuring your application into cohesive, self-contained modules, you ensure your project remains clean, maintainable, and ready for enterprise-level expansion.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=762841eb8dba" width="1" height="1" alt="">]]></content:encoded>
        </item>
    </channel>
</rss>