🏠 Home / Hub

🔷 TypeScript Lesson 04 — Classes & OOP

← Back to TypeScript Menu  |  🏠 Hub

1. Class Basics

class User {
  // Properties with types
  id:       number;
  name:     string;
  email:    string;
  private   password: string;    // private — outside ကနေ access မရ
  protected role: string;        // protected — subclass access ရ
  readonly  createdAt: Date;     // readonly — after init မပြောင်းရ

  constructor(id: number, name: string, email: string, password: string) {
    this.id        = id;
    this.name      = name;
    this.email     = email;
    this.password  = password;
    this.role      = "user";
    this.createdAt = new Date();
  }

  // Method
  greet(): string {
    return `Hello, I'm ${this.name}`;
  }

  // Getter (property-like access)
  get displayName(): string {
    return `${this.name} (${this.role})`;
  }

  // Setter
  set newPassword(pwd: string) {
    if (pwd.length < 8) throw new Error("Too short!");
    this.password = pwd;
  }
}

const user = new User(1, "Ko Ko", "ko@test.com", "pass1234");
console.log(user.name);         // "Ko Ko" ✅
console.log(user.password);     // ❌ Error: private!
console.log(user.displayName);  // "Ko Ko (user)"

2. Shorthand Constructor (Parameter Properties)

// TypeScript shortcut: access modifier in constructor params
class Product {
  constructor(
    public  readonly id:    number,
    public           name:  string,
    public           price: number,
    private          stock: number = 0
  ) {}
  // → automatically creates and assigns: this.id, this.name, this.price, this.stock
  // No need to declare properties or assign in body!

  isInStock(): boolean { return this.stock > 0; }
  addStock(qty: number): void { this.stock += qty; }
}

const laptop = new Product(1, "Laptop", 1200, 10);
console.log(laptop.name);    // "Laptop"
console.log(laptop.stock);   // ❌ private!

3. Inheritance & Interfaces

interface Serializable {
  serialize(): string;
  toJSON(): object;
}

class BaseEntity {
  constructor(public id: number, public createdAt: Date = new Date()) {}

  toString(): string { return `Entity(${this.id})`; }
}

class User extends BaseEntity implements Serializable {
  constructor(
    id: number,
    public name: string,
    public email: string,
    protected role: "admin" | "user" = "user"
  ) {
    super(id);   // ← call parent constructor!
  }

  serialize(): string { return JSON.stringify(this.toJSON()); }

  toJSON() {
    return { id: this.id, name: this.name, email: this.email, role: this.role };
  }
}

class AdminUser extends User {
  constructor(id: number, name: string, email: string, public permissions: string[]) {
    super(id, name, email, "admin");
  }

  hasPermission(perm: string): boolean {
    return this.permissions.includes(perm);
  }
}

const admin = new AdminUser(1, "Ko Ko", "ko@test.com", ["read", "write", "delete"]);
console.log(admin.hasPermission("delete"));  // true
console.log(admin.serialize());

4. Abstract Classes

// Abstract = cannot instantiate directly, must be subclassed
abstract class Repository<T> {
  abstract findAll(): Promise<T[]>;
  abstract findById(id: number): Promise<T | null>;
  abstract create(data: Partial<T>): Promise<T>;
  abstract update(id: number, data: Partial<T>): Promise<T>;
  abstract delete(id: number): Promise<boolean>;

  // Concrete method (shared by all)
  async exists(id: number): Promise<boolean> {
    const item = await this.findById(id);
    return item !== null;
  }
}

interface User { id: number; name: string; email: string; }

class UserRepository extends Repository<User> {
  private users: User[] = [];

  async findAll() { return this.users; }
  async findById(id: number) { return this.users.find(u => u.id === id) || null; }
  async create(data: Omit<User, 'id'>) {
    const user = { id: this.users.length + 1, ...data };
    this.users.push(user);
    return user;
  }
  async update(id: number, data: Partial<User>) {
    const idx = this.users.findIndex(u => u.id === id);
    this.users[idx] = { ...this.users[idx], ...data };
    return this.users[idx];
  }
  async delete(id: number) {
    const idx = this.users.findIndex(u => u.id === id);
    if (idx === -1) return false;
    this.users.splice(idx, 1);
    return true;
  }
}

const repo = new UserRepository();
await repo.create({ name: "Ko Ko", email: "ko@test.com" });
💡 Repository pattern = database operations ကို abstract ထားနည်း — real backend projects မှာ ပုံမှန် pattern

← TS 03  |  Next: TS 05 → Generics →

📌 Study Checklist