Crack the Code: Understanding TypeScript Classes with Ease 👨‍🏫🔍

OohnohassaniOohnohassani
6 min read

Hey there! 👋 Welcome to Gocoding — my little corner of the web where I document what I'm learning in public, one blog at a time. I’m Hassani, just a noob navigating front-end development, scared but doing it anyway 💻💡.

In this post, we’re exploring TypeScript classes — what they are, why they matter, and how to use them. We’ll talk about normal classes, abstract classes, and the Singleton pattern (aka the one-object-to-rule-them-all class 😄). Expect examples, analogies, and lots of emojis to keep it fun and super beginner-friendly.

Let’s grow together, one concept at a time 🌱
#LearningInPublic #MyDigitalGarden

When you're building software — whether it's a sleek front-end app or a massive enterprise tool — how you organize your code matters. That’s where classes come in. They're like special containers that hold both data (called properties) and actions (called methods). If you’ve used classes in JavaScript, then you’ll feel right at home here, because TypeScript builds on top of that — just with extra structure and type safety. ❤️

This blog is perfect if you already have some knowledge of JavaScript classes. If you don’t, don’t worry! You can catch up first with our beginner-friendly JavaScript OOP and Classes blog before diving in here. 👈

In this post, we’ll explore:

  • What are normal classes and how to use them

  • What are abstract classes, why they're important, and how they enforce structure

  • What is the singleton pattern and when it shines

  • Real-world examples, simple analogies, pros & cons

  • Plus a quick quiz, a wrap-up, and extra learning links! 🎉

1️⃣Normal Classes – Reusable Blueprints 🏗️

Let’s start with the basics. A normal class in TypeScript is like a cookie cutter 🍪 — once you make it, you can use it to create as many cookies (objects) as you want. Each cookie might be decorated differently (different data), but they’re made from the same mold (class). Classes help you avoid repeating yourself, because you define the structure once, then just create new instances from it.

Here's an example. Let’s say you want to represent dogs in your code. Instead of rewriting name and bark functions again and again, you define a class and reuse it:

class Dog {
  name: string;

  constructor(name: string) {
    this.name = name;
  }

  bark(): void {
    console.log(`${this.name} says Woof! 🐶`);
  }
}

const dog1 = new Dog("Buddy");
const dog2 = new Dog("Max");

dog1.bark(); // Buddy says Woof!
dog2.bark(); // Max says Woof!

So, instead of duplicating logic, you use the same class and just pass different names. It’s clean, efficient, and scalable.

💡 When to use?
Use normal classes when you need to create multiple similar objects with shared structure and behavior. Think of users, orders, products — anything that appears in numbers.

👍 Why it’s good: Easy to reuse, organize code, and make your app DRY (Don’t Repeat Yourself).
👎 Downside? None really, unless you try to force too many responsibilities into one class. Keep it focused!

2️⃣Abstract Classes – Rules Without Details 📘

Now let’s talk about abstract classes, which are like a rulebook 📜 for other classes to follow. You can’t create objects directly from an abstract class. Instead, you use it to define the structure, and then other classes (called child classes) fill in the blanks.

Imagine you're designing a payment system. You know every payment needs a pay() method — but how it’s paid (credit card, cash, crypto) will differ. So, you create an abstract class with the common rule (pay) and let others implement it their own way.

abstract class Payment {
  abstract pay(amount: number): void;

  printReceipt(): void {
    console.log("🧾 Receipt printed!");
  }
}

class CashPayment extends Payment {
  pay(amount: number): void {
    console.log(`💵 Paid $${amount} in cash.`);
  }
}

class CardPayment extends Payment {
  pay(amount: number): void {
    console.log(`💳 Paid $${amount} by card.`);
  }
}

const payWithCard = new CardPayment();
payWithCard.pay(100); // 💳 Paid $100 by card.
payWithCard.printReceipt(); // 🧾 Receipt printed!

This way, all payment types must have a pay() method, but they can each do it their own way. It’s like telling all students to wear uniforms, but letting them pick their shoe color. 👞👟👠

💡 When to use?
Use abstract classes when you want multiple related classes to follow the same contract — a shared method or property — while still keeping their own personality.

👍 Why it’s good: Enforces structure and consistency. Shared code lives in the base class.
👎 Downside? Slightly more setup. And remember, you can’t create an object directly from an abstract class.

3️⃣Singleton Pattern – One to Rule Them All 👑

Now this is an interesting one: the Singleton pattern. A singleton ensures you only ever have one instance of a class, no matter how many times you try to access it. It’s like having a family car 🚗 — everyone can use it, but there’s just one in the garage.

You usually use singletons for global shared resources — like a settings manager, or database connection. Instead of creating multiple versions and risking conflicts, you create just one and share it.

Here’s how it looks:

class Settings {
  private static instance: Settings;
  public theme: string = "light";

  private constructor() {} // Hide the constructor

  static getInstance(): Settings {
    if (!Settings.instance) {
      Settings.instance = new Settings();
    }
    return Settings.instance;
  }
}

const appSettings1 = Settings.getInstance();
const appSettings2 = Settings.getInstance();

console.log(appSettings1 === appSettings2); // true ✅

No matter how many times you call getInstance(), you’ll get the same object. That’s the magic! 🪄

💡 When to use?
Use singletons for shared things like settings, loggers, or caches. They're useful when only one instance makes sense in your whole app.

👍 Why it’s good: Avoids duplicates, keeps things consistent, and saves memory.
👎 Downside? Can make unit testing harder. And overusing it might lead to global state problems if not managed carefully.

🧠 Quick Quiz (Test Yourself!)

  1. What type of class acts as a rulebook but cannot be directly instantiated?
    👉 Answer: Abstract Class 📘

  2. Which class ensures only one object exists?
    👉 Answer: Singleton 👑

  3. True or False: You can create as many objects as you want from a normal class.
    👉 Answer: True ✅

📝 TL;DR (Too Long; Didn’t Read)

  • Normal Class = Cookie cutter 🍪. Make lots of similar objects.

  • Abstract Class = Rulebook 📘. Tells child classes what they must do.

  • Singleton = One family car 🚗. Only one instance shared by all.

Use normal classes when you need to make many objects, abstract classes when enforcing structure, and singleton when one instance is enough. TypeScript makes these patterns even safer with types and structure! 🛡️

📚 References & Further Reading

Look at you! You just cruised through normal classes, abstract classes, and even wrangled the mighty Singleton like a pro 💪. Who said TypeScript has to be scary? Definitely not us!

If your brain feels a bit fried right now, that’s totally normal — learning something new is hard. But hey, you’re doing it anyway. That’s the magic. ✨

Feel free to reread, play with the code, and shout "AHA!" moments into the void (or tweet them, your call).
And if you got this far? You’re not a noob. You’re a #LearningInPublic legend. 💥

Until next time,
Stay curious, break stuff (responsibly), and may your bugs be tiny and easy to squash! 🐛🔨

#MyDigitalGarden #DoItScared #Gocoding

💬 Got questions? Drop a comment below and let’s geek out on TypeScript together! 🧠💬
Thanks for reading and happy coding, dev friend! ✨💻

0
Subscribe to my newsletter

Read articles from Oohnohassani directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Oohnohassani
Oohnohassani

Hi 👋 I'm a developer with experience in building websites with beautiful designs and user friendly interfaces. I'm experienced in front-end development using languages such as Html5, Css3, TailwindCss, Javascript, Typescript, react.js & redux and NextJs 🚀