Classes, Access Modifiers & Abstract Classes
📖 Concept
TypeScript enhances JavaScript classes with access modifiers, abstract classes, parameter properties, and interface implementation.
Access modifiers:
public— Accessible anywhere (default)private— Only within the class itself (TS-only enforcement)protected— Within the class and its subclasses#field— True JavaScript private (runtime enforcement, ES2022)
Parameter properties are a shorthand: constructor(public name: string) automatically creates and assigns this.name.
Abstract classes define blueprints that can't be instantiated directly — subclasses MUST implement abstract methods.
Interface implementation (class Foo implements Bar) ensures a class satisfies a contract. Unlike structural typing, implements provides an explicit check.
override keyword (TS 4.3) explicitly marks methods overriding parent methods — catches typos in method names.
🏠 Real-world analogy: Access modifiers are like building security levels. public is the lobby — anyone can enter. protected is the office floor — only employees and their teams. private is the server room — only specific personnel. Abstract classes are like blueprints — you can't live in a blueprint, but you build real houses from them.
💻 Code Example
1// Access modifiers + parameter properties2class User {3 // Parameter properties — shorthand for declare + assign4 constructor(5 public readonly id: number,6 public name: string,7 private email: string,8 protected role: string = "user"9 ) {}1011 getEmail(): string {12 return this.email; // ✅ private accessible inside class13 }14}1516const user = new User(1, "Alice", "alice@test.com");17user.name; // ✅ public18// user.email; // ❌ Error: 'email' is private19// user.role; // ❌ Error: 'role' is protected20// user.id = 2; // ❌ Error: readonly2122// Protected access in subclass23class Admin extends User {24 constructor(id: number, name: string, email: string) {25 super(id, name, email, "admin");26 }2728 getRole(): string {29 return this.role; // ✅ protected accessible in subclass30 }31}3233// Abstract class — can't instantiate directly34abstract class Shape {35 abstract area(): number; // Must be implemented36 abstract perimeter(): number; // Must be implemented3738 // Concrete method — shared by all subclasses39 describe(): string {40 return `Shape with area ${this.area().toFixed(2)}`;41 }42}4344// const s = new Shape(); // ❌ Error: Cannot create instance of abstract class4546class Circle extends Shape {47 constructor(public radius: number) {48 super();49 }5051 area(): number {52 return Math.PI * this.radius ** 2;53 }5455 perimeter(): number {56 return 2 * Math.PI * this.radius;57 }58}5960// Implements — class satisfies an interface61interface Serializable {62 serialize(): string;63 deserialize(data: string): void;64}6566interface Loggable {67 log(): void;68}6970class Config implements Serializable, Loggable {71 constructor(private data: Record<string, unknown> = {}) {}7273 serialize(): string {74 return JSON.stringify(this.data);75 }7677 deserialize(data: string): void {78 this.data = JSON.parse(data);79 }8081 log(): void {82 console.log(this.data);83 }84}8586// Override keyword (TS 4.3+, enable noImplicitOverride)87class Animal {88 speak(): string {89 return "...";90 }91}9293class Dog extends Animal {94 override speak(): string { // Explicit override95 return "Woof!";96 }9798 // override spek(): string { // ❌ Error: no method named 'spek' to override99 // return "typo caught!";100 // }101}102103// Generic class104class Repository<T extends { id: number }> {105 private items = new Map<number, T>();106107 add(item: T): void {108 this.items.set(item.id, item);109 }110111 findById(id: number): T | undefined {112 return this.items.get(id);113 }114115 getAll(): T[] {116 return Array.from(this.items.values());117 }118}119const userRepo = new Repository<User>();
🏋️ Practice Exercise
Mini Exercise:
- Create a class with
public,private,protected, andreadonlyproperties — test each from outside - Use parameter properties to simplify a constructor
- Create an abstract
Vehicleclass with concrete and abstract methods, then implementCarandTruck - Implement multiple interfaces on a single class
- Use the
overridekeyword and see what happens with a typo in the method name
⚠️ Common Mistakes
Using TS
privatefor security — it's compile-time only; at runtime, the property is still accessible. Use#fieldfor true runtime privacyForgetting to call
super()in the subclass constructor before usingthis— TypeScript enforces this and throws a compile errorNot knowing that
implementsdoesn't add anything at runtime — it's a compile-time check only. The class must still provide all propertiesOver-using abstract classes when an interface would suffice — abstract classes add a runtime prototype chain; interfaces are zero-cost
Forgetting that parameter properties only work in constructors —
publicon a regular method parameter doesn't create a property
💼 Interview Questions
🎤 Mock Interview
Practice a live interview for Classes, Access Modifiers & Abstract Classes