+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Part 11 of 355

๐Ÿ”— Interfaces in TypeScript: Building Contracts for Your Code

Master TypeScript interfaces to create powerful type contracts, enforce object shapes, and build flexible, maintainable applications ๐Ÿš€

๐ŸŒฑBeginner
25 min read

Prerequisites

  • Basic TypeScript types knowledge ๐Ÿ“
  • Understanding of objects in JavaScript โšก
  • Functions and parameters basics ๐Ÿ’ป

What you'll learn

  • Create and use interfaces effectively ๐ŸŽฏ
  • Understand optional and readonly properties ๐Ÿ—๏ธ
  • Master interface inheritance and extension ๐Ÿ”
  • Apply interfaces in real-world scenarios โœจ

๐ŸŽฏ Introduction

Welcome to the world of TypeScript interfaces! ๐ŸŽ‰ If types are the atoms of TypeScript, interfaces are the molecules - they combine simple types into powerful structures.

Think of interfaces as blueprints for objects ๐Ÿ—๏ธ. Just like an architectโ€™s blueprint ensures every room has doors and windows in the right places, interfaces ensure your objects have the right properties with the right types. Theyโ€™re contracts that say โ€œif you want to be this type of thing, you must have these properties!โ€

By the end of this tutorial, youโ€™ll be creating interfaces like a pro, making your code more predictable, maintainable, and delightful to work with! Letโ€™s build! ๐ŸŠโ€โ™‚๏ธ

๐Ÿ“š Understanding Interfaces

๐Ÿค” What Are Interfaces?

Interfaces define the shape of objects in TypeScript. Theyโ€™re like a checklist ๐Ÿ“‹ that objects must satisfy to be considered a certain type.

Unlike classes (which are blueprints for creating objects), interfaces are purely for type-checking. They exist only at compile time and disappear in the JavaScript output:

  • โœจ Define object structures
  • ๐Ÿš€ Enable type checking
  • ๐Ÿ›ก๏ธ Provide IntelliSense support
  • ๐Ÿ“– Document your codeโ€™s expectations

๐Ÿ’ก Interface vs Type Alias

Both can describe object shapes, but interfaces have superpowers:

// ๐ŸŽฏ Interface - preferred for objects
interface User {
  name: string;
  age: number;
}

// ๐ŸŽจ Type alias - more flexible
type UserType = {
  name: string;
  age: number;
};

// ๐Ÿ’ก Key differences:
// 1. Interfaces can be extended and merged
interface User {
  email?: string; // This merges with the above!
}

// 2. Interfaces are better for OOP
class Employee implements User {
  name = "Alice";
  age = 30;
  email = "[email protected]";
}

// 3. Type aliases can represent primitives and unions
type ID = string | number; // Can't do this with interface

๐Ÿ”ง Basic Interface Syntax

๐Ÿ“ Creating Your First Interface

Letโ€™s start with simple interfaces:

// ๐ŸŽจ Basic interface structure
interface Person {
  firstName: string;
  lastName: string;
  age: number;
}

// โœ… Object that matches the interface
const student: Person = {
  firstName: "Emma",
  lastName: "Watson",
  age: 25
};

// โŒ Missing required property
// const incomplete: Person = {
//   firstName: "John",
//   age: 30
// }; // Error: Property 'lastName' is missing

// ๐ŸŽฏ Using interfaces as function parameters
function greetPerson(person: Person): string {
  return `Hello, ${person.firstName} ${person.lastName}! ๐Ÿ‘‹`;
}

console.log(greetPerson(student)); // "Hello, Emma Watson! ๐Ÿ‘‹"

๐ŸŽจ Optional Properties

Not every property is required - use ? for optional ones:

// ๐Ÿ  Real estate listing interface
interface House {
  address: string;
  bedrooms: number;
  bathrooms: number;
  garage?: boolean;      // Optional - not all houses have garages
  pool?: boolean;        // Optional - luxury feature
  yearBuilt?: number;    // Optional - might not know
}

// โœ… Valid houses with different optional properties
const cozyHome: House = {
  address: "123 Main St",
  bedrooms: 3,
  bathrooms: 2
  // No garage, pool, or yearBuilt - that's OK!
};

const luxuryHome: House = {
  address: "456 Ocean View",
  bedrooms: 5,
  bathrooms: 4,
  garage: true,
  pool: true,
  yearBuilt: 2020
};

// ๐ŸŽฏ Function handling optional properties
function describeHouse(house: House): string {
  let description = `๐Ÿ  ${house.address}: ${house.bedrooms}BR/${house.bathrooms}BA`;
  
  if (house.garage) description += " | Garage โœ…";
  if (house.pool) description += " | Pool ๐ŸŠ";
  if (house.yearBuilt) description += ` | Built ${house.yearBuilt}`;
  
  return description;
}

๐Ÿ”’ Readonly Properties

Some properties shouldnโ€™t change after creation:

// ๐Ÿ“š Book interface with immutable properties
interface Book {
  readonly isbn: string;      // Can't change ISBN
  readonly author: string;    // Can't change author
  title: string;             // Can change (editions)
  price: number;             // Can change (sales)
}

const typeScriptBook: Book = {
  isbn: "978-1-491-96720-4",
  author: "Boris Cherny",
  title: "Programming TypeScript",
  price: 39.99
};

// โœ… Can modify mutable properties
typeScriptBook.price = 29.99; // On sale! ๐ŸŽ‰

// โŒ Cannot modify readonly properties
// typeScriptBook.isbn = "123-4-567-89012-3"; // Error!
// typeScriptBook.author = "Someone Else"; // Error!

// ๐Ÿ›ก๏ธ Readonly arrays
interface TeamRoster {
  readonly players: readonly string[]; // Double readonly!
}

const basketballTeam: TeamRoster = {
  players: ["LeBron", "Curry", "Durant", "Giannis", "Jokic"]
};

// โŒ Can't reassign or modify
// basketballTeam.players = ["New", "Players"]; // Error!
// basketballTeam.players.push("New Player"); // Error!

๐Ÿ’ก Advanced Interface Features

๐ŸŽฏ Index Signatures

When you donโ€™t know all property names ahead of time:

// ๐Ÿ“Š Dynamic configuration interface
interface Config {
  apiUrl: string;                    // Known property
  timeout: number;                   // Known property
  [key: string]: string | number;    // Any other string key!
}

const appConfig: Config = {
  apiUrl: "https://api.example.com",
  timeout: 5000,
  retryAttempts: 3,                  // Dynamic property
  environment: "production",         // Dynamic property
  maxConnections: 100                // Dynamic property
};

// ๐ŸŽฎ Game scores with dynamic player names
interface GameScores {
  gameName: string;
  [playerName: string]: string | number; // Player names as keys
}

const arcadeScores: GameScores = {
  gameName: "Space Invaders",
  "Alice": 15000,
  "Bob": 12000,
  "Charlie": 18000,
  "ๆ–ฐใ—ใ„ใƒ—ใƒฌใ‚คใƒคใƒผ": 20000 // Any string works!
};

// ๐Ÿ’ก Accessing dynamic properties
for (const player in arcadeScores) {
  if (player !== "gameName") {
    console.log(`${player}: ${arcadeScores[player]} points ๐ŸŽฎ`);
  }
}

๐Ÿ—๏ธ Extending Interfaces

Build complex interfaces from simple ones:

// ๐Ÿงฑ Base interfaces
interface Animal {
  name: string;
  age: number;
}

interface Mammal extends Animal {
  furColor: string;
  numberOfLegs: number;
}

interface Pet extends Animal {
  owner: string;
  isVaccinated: boolean;
}

// ๐Ÿ• Combining multiple interfaces
interface Dog extends Mammal, Pet {
  breed: string;
  goodBoy: boolean; // Always true! ๐Ÿฅฐ
}

const myDog: Dog = {
  // From Animal
  name: "Buddy",
  age: 3,
  // From Mammal
  furColor: "golden",
  numberOfLegs: 4,
  // From Pet
  owner: "Sarah",
  isVaccinated: true,
  // Dog-specific
  breed: "Golden Retriever",
  goodBoy: true
};

// ๐Ÿข Real-world example: Employee hierarchy
interface Person {
  firstName: string;
  lastName: string;
  email: string;
}

interface Employee extends Person {
  employeeId: string;
  department: string;
  hireDate: Date;
}

interface Manager extends Employee {
  teamMembers: Employee[];
  budget: number;
}

// ๐ŸŽฏ Creating a manager
const techLead: Manager = {
  firstName: "Alex",
  lastName: "Chen",
  email: "[email protected]",
  employeeId: "EMP001",
  department: "Engineering",
  hireDate: new Date("2020-01-15"),
  teamMembers: [],
  budget: 500000
};

๐Ÿ”ง Function Types in Interfaces

Interfaces can describe functions too:

// ๐ŸŽฏ Function type interface
interface MathOperation {
  (x: number, y: number): number;
}

const add: MathOperation = (x, y) => x + y;
const multiply: MathOperation = (x, y) => x * y;
const subtract: MathOperation = (x, y) => x - y;

// ๐Ÿงฎ Calculator interface with methods
interface Calculator {
  // Method signatures
  add(x: number, y: number): number;
  subtract(x: number, y: number): number;
  multiply(x: number, y: number): number;
  divide(x: number, y: number): number;
  
  // Property that's a function
  lastOperation: MathOperation | null;
}

class BasicCalculator implements Calculator {
  lastOperation: MathOperation | null = null;
  
  add(x: number, y: number): number {
    this.lastOperation = add;
    return x + y;
  }
  
  subtract(x: number, y: number): number {
    this.lastOperation = subtract;
    return x - y;
  }
  
  multiply(x: number, y: number): number {
    this.lastOperation = multiply;
    return x * y;
  }
  
  divide(x: number, y: number): number {
    if (y === 0) throw new Error("Division by zero! ๐Ÿšซ");
    this.lastOperation = (a, b) => a / b;
    return x / y;
  }
}

// ๐ŸŽฎ Event handler interface
interface ClickHandler {
  (event: MouseEvent): void;
}

interface Button {
  label: string;
  onClick: ClickHandler;
  onDoubleClick?: ClickHandler; // Optional handler
}

const saveButton: Button = {
  label: "Save ๐Ÿ’พ",
  onClick: (e) => {
    console.log("Saving...");
    e.preventDefault();
  }
};

๐Ÿš€ Practical Examples

๐Ÿ›’ E-commerce Product System

Letโ€™s build a real product management system:

// ๐Ÿท๏ธ Product interfaces
interface Product {
  id: string;
  name: string;
  price: number;
  description: string;
  inStock: boolean;
}

interface DigitalProduct extends Product {
  downloadUrl: string;
  fileSize: number; // in MB
  license: "single" | "multi" | "enterprise";
}

interface PhysicalProduct extends Product {
  weight: number; // in kg
  dimensions: {
    width: number;
    height: number;
    depth: number;
  };
  shippingCost: number;
}

interface Review {
  userId: string;
  rating: 1 | 2 | 3 | 4 | 5;
  comment: string;
  date: Date;
  helpful: number;
}

interface ProductWithReviews extends Product {
  reviews: Review[];
  averageRating: number;
}

// ๐Ÿ›๏ธ Shopping cart
interface CartItem {
  product: Product;
  quantity: number;
}

interface ShoppingCart {
  items: CartItem[];
  customerId: string;
  createdAt: Date;
  
  addItem(product: Product, quantity: number): void;
  removeItem(productId: string): void;
  getTotalPrice(): number;
  checkout(): Order;
}

interface Order {
  orderId: string;
  items: CartItem[];
  totalPrice: number;
  status: "pending" | "processing" | "shipped" | "delivered";
  orderDate: Date;
}

// ๐Ÿ—๏ธ Implementation
class OnlineShoppingCart implements ShoppingCart {
  items: CartItem[] = [];
  customerId: string;
  createdAt: Date;
  
  constructor(customerId: string) {
    this.customerId = customerId;
    this.createdAt = new Date();
  }
  
  addItem(product: Product, quantity: number): void {
    const existingItem = this.items.find(item => item.product.id === product.id);
    
    if (existingItem) {
      existingItem.quantity += quantity;
    } else {
      this.items.push({ product, quantity });
    }
    
    console.log(`Added ${quantity}x ${product.name} to cart ๐Ÿ›’`);
  }
  
  removeItem(productId: string): void {
    this.items = this.items.filter(item => item.product.id !== productId);
    console.log(`Removed item from cart ๐Ÿ—‘๏ธ`);
  }
  
  getTotalPrice(): number {
    return this.items.reduce((total, item) => {
      return total + (item.product.price * item.quantity);
    }, 0);
  }
  
  checkout(): Order {
    return {
      orderId: `ORD-${Date.now()}`,
      items: [...this.items],
      totalPrice: this.getTotalPrice(),
      status: "pending",
      orderDate: new Date()
    };
  }
}

// ๐ŸŽฎ Usage
const laptop: PhysicalProduct = {
  id: "LAPTOP-001",
  name: "TypeScript Developer Laptop",
  price: 1299.99,
  description: "Perfect for TypeScript development",
  inStock: true,
  weight: 2.5,
  dimensions: { width: 35, height: 25, depth: 2 },
  shippingCost: 29.99
};

const course: DigitalProduct = {
  id: "COURSE-001",
  name: "Master TypeScript Course",
  price: 89.99,
  description: "Learn TypeScript from zero to hero",
  inStock: true,
  downloadUrl: "https://downloads.example.com/course",
  fileSize: 2048,
  license: "single"
};

const cart = new OnlineShoppingCart("CUST-123");
cart.addItem(laptop, 1);
cart.addItem(course, 2);

console.log(`Total: $${cart.getTotalPrice().toFixed(2)} ๐Ÿ’ฐ`);

๐ŸŽฎ Game Development Interfaces

Building a game character system:

// ๐Ÿฆธ Character system interfaces
interface Stats {
  health: number;
  maxHealth: number;
  mana: number;
  maxMana: number;
  strength: number;
  defense: number;
  speed: number;
}

interface Ability {
  name: string;
  description: string;
  manaCost: number;
  cooldown: number;
  damage?: number;
  healing?: number;
  icon: string; // emoji for fun!
}

interface Character {
  id: string;
  name: string;
  level: number;
  experience: number;
  stats: Stats;
  abilities: Ability[];
}

interface Player extends Character {
  username: string;
  gold: number;
  inventory: Item[];
  achievements: Achievement[];
}

interface Enemy extends Character {
  lootTable: LootDrop[];
  aggressionLevel: "passive" | "neutral" | "aggressive";
  respawnTime: number;
}

interface Item {
  id: string;
  name: string;
  type: "weapon" | "armor" | "consumable" | "quest";
  rarity: "common" | "rare" | "epic" | "legendary";
  value: number;
  icon: string;
}

interface LootDrop {
  item: Item;
  dropChance: number; // 0-1
}

interface Achievement {
  id: string;
  name: string;
  description: string;
  icon: string;
  unlockedAt?: Date;
}

// ๐ŸŽฎ Battle system
interface BattleAction {
  attacker: Character;
  target: Character;
  ability: Ability;
  execute(): BattleResult;
}

interface BattleResult {
  damage?: number;
  healing?: number;
  statusEffects?: string[];
  critical: boolean;
}

// ๐Ÿ—๏ธ Implementation example
class FireballAbility implements BattleAction {
  constructor(
    public attacker: Character,
    public target: Character,
    public ability: Ability
  ) {}
  
  execute(): BattleResult {
    const baseDamage = this.ability.damage || 0;
    const attackPower = this.attacker.stats.strength;
    const defense = this.target.stats.defense;
    
    const damage = Math.max(1, baseDamage + attackPower - defense);
    const critical = Math.random() < 0.2; // 20% crit chance
    
    return {
      damage: critical ? damage * 2 : damage,
      critical,
      statusEffects: ["burning"]
    };
  }
}

// ๐ŸŽฏ Create a player
const hero: Player = {
  id: "PLAYER-001",
  name: "TypeScript Hero",
  username: "TSMaster",
  level: 10,
  experience: 2500,
  gold: 1000,
  stats: {
    health: 100,
    maxHealth: 100,
    mana: 50,
    maxMana: 50,
    strength: 15,
    defense: 10,
    speed: 12
  },
  abilities: [
    {
      name: "Fireball",
      description: "Launch a blazing fireball",
      manaCost: 10,
      cooldown: 3,
      damage: 25,
      icon: "๐Ÿ”ฅ"
    },
    {
      name: "Heal",
      description: "Restore health",
      manaCost: 15,
      cooldown: 5,
      healing: 30,
      icon: "๐Ÿ’š"
    }
  ],
  inventory: [],
  achievements: []
};

โš ๏ธ Common Pitfalls and Solutions

๐Ÿ˜ฑ Pitfall 1: Interface vs Implementation Confusion

// โŒ Common mistake - trying to add implementation to interface
interface Calculator {
  add(a: number, b: number): number {
    return a + b; // Error! Interfaces can't have implementation
  }
}

// โœ… Correct approach - interface defines shape only
interface Calculator {
  add(a: number, b: number): number;
}

// Implementation goes in the class
class BasicCalc implements Calculator {
  add(a: number, b: number): number {
    return a + b;
  }
}

๐Ÿคฏ Pitfall 2: Optional Property Misuse

interface User {
  name: string;
  email?: string;
}

// โŒ Dangerous assumption
function sendEmail(user: User) {
  // This could crash if email is undefined!
  console.log(`Sending to ${user.email.toLowerCase()}`);
}

// โœ… Safe handling
function sendEmailSafely(user: User) {
  if (user.email) {
    console.log(`Sending to ${user.email.toLowerCase()} ๐Ÿ“ง`);
  } else {
    console.log("No email address provided โš ๏ธ");
  }
}

๐Ÿ˜ต Pitfall 3: Excess Property Checks

interface Point {
  x: number;
  y: number;
}

// โŒ Excess property error with object literals
const point3D: Point = {
  x: 10,
  y: 20,
  z: 30 // Error! 'z' does not exist in type 'Point'
};

// โœ… Solutions:
// 1. Use type assertion
const point3D = {
  x: 10,
  y: 20,
  z: 30
} as Point;

// 2. Use index signature
interface FlexiblePoint {
  x: number;
  y: number;
  [key: string]: number;
}

// 3. Assign to variable first
const myPoint = { x: 10, y: 20, z: 30 };
const point2D: Point = myPoint; // OK!

๐Ÿ› ๏ธ Best Practices

๐ŸŽฏ Interface Best Practices

  1. ๐Ÿ“ Use Descriptive Names: Make intent clear

    // โŒ Vague
    interface Data { }
    
    // โœ… Descriptive
    interface UserProfile { }
  2. ๐Ÿ—๏ธ Start Simple, Extend Later: Build incrementally

    // Start with basics
    interface User {
      id: string;
      name: string;
    }
    
    // Extend as needed
    interface AuthenticatedUser extends User {
      token: string;
      permissions: string[];
    }
  3. ๐ŸŽจ Use Readonly for Immutability: Prevent accidental changes

    interface Config {
      readonly apiUrl: string;
      readonly apiKey: string;
    }
  4. โœจ Prefer Interfaces for Object Shapes: More flexible than types

    // โœ… Interface for objects
    interface Person {
      name: string;
      age: number;
    }
    
    // Type for unions/primitives
    type ID = string | number;
  5. ๐Ÿ”ง Document Complex Interfaces: Help future developers

    /**
     * Represents a user in our system
     * @property isActive - Whether the user can log in
     * @property lastLogin - UTC timestamp of last login
     */
    interface SystemUser {
      id: string;
      username: string;
      isActive: boolean;
      lastLogin?: Date;
    }

๐Ÿงช Hands-On Exercise

๐ŸŽฏ Challenge: Build a Library Management System

Create interfaces for a library system:

๐Ÿ“‹ Requirements:

  • โœ… Books with ISBN, authors, and availability
  • ๐Ÿท๏ธ Members with borrowing limits
  • ๐Ÿ‘ฅ Borrowing records with due dates
  • ๐Ÿ“… Reservation system
  • ๐ŸŽจ Different media types (books, DVDs, audiobooks)

๐Ÿš€ Bonus Points:

  • Add late fee calculation
  • Implement search functionality
  • Create librarian interface with special permissions

๐Ÿ’ก Solution

๐Ÿ” Click to see solution
// ๐Ÿ“š Base interfaces
interface MediaItem {
  id: string;
  title: string;
  publisher: string;
  publishYear: number;
  available: boolean;
  location: string; // Shelf location
}

interface Book extends MediaItem {
  type: "book";
  isbn: string;
  authors: string[];
  pages: number;
  genre: string[];
}

interface DVD extends MediaItem {
  type: "dvd";
  director: string;
  duration: number; // minutes
  rating: "G" | "PG" | "PG-13" | "R";
}

interface AudioBook extends MediaItem {
  type: "audiobook";
  narrator: string;
  duration: number; // minutes
  format: "CD" | "digital";
}

type LibraryItem = Book | DVD | AudioBook;

// ๐Ÿ‘ฅ Member interfaces
interface Member {
  id: string;
  name: string;
  email: string;
  phone: string;
  memberSince: Date;
  isActive: boolean;
  borrowingLimit: number;
}

interface Student extends Member {
  memberType: "student";
  studentId: string;
  school: string;
}

interface Adult extends Member {
  memberType: "adult";
  occupation?: string;
}

type LibraryMember = Student | Adult;

// ๐Ÿ“‹ Transaction interfaces
interface BorrowingRecord {
  id: string;
  memberId: string;
  itemId: string;
  borrowDate: Date;
  dueDate: Date;
  returnDate?: Date;
  lateFee?: number;
}

interface Reservation {
  id: string;
  memberId: string;
  itemId: string;
  reservationDate: Date;
  expiryDate: Date;
  status: "active" | "fulfilled" | "expired";
}

// ๐Ÿ›๏ธ Library system interface
interface LibrarySystem {
  items: LibraryItem[];
  members: LibraryMember[];
  borrowingRecords: BorrowingRecord[];
  reservations: Reservation[];
  
  // Media management
  addItem(item: LibraryItem): void;
  removeItem(itemId: string): boolean;
  searchItems(query: string): LibraryItem[];
  
  // Member management
  registerMember(member: LibraryMember): void;
  findMember(memberId: string): LibraryMember | undefined;
  
  // Borrowing operations
  borrowItem(memberId: string, itemId: string): BorrowingRecord;
  returnItem(recordId: string): void;
  calculateLateFee(record: BorrowingRecord): number;
  
  // Reservation operations
  reserveItem(memberId: string, itemId: string): Reservation;
  cancelReservation(reservationId: string): void;
}

// ๐Ÿ‘จโ€๐Ÿ’ผ Librarian interface
interface Librarian extends Member {
  employeeId: string;
  permissions: Permission[];
  
  // Special operations
  waiveLateFee(recordId: string): void;
  extendDueDate(recordId: string, days: number): void;
  generateReport(type: ReportType): Report;
}

interface Permission {
  action: "add_item" | "remove_item" | "modify_member" | "waive_fees";
  granted: boolean;
}

type ReportType = "overdue" | "popular_items" | "member_activity";

interface Report {
  type: ReportType;
  generatedAt: Date;
  data: any;
}

// ๐Ÿ—๏ธ Implementation example
class PublicLibrary implements LibrarySystem {
  items: LibraryItem[] = [];
  members: LibraryMember[] = [];
  borrowingRecords: BorrowingRecord[] = [];
  reservations: Reservation[] = [];
  
  private lateFeePerDay = 0.50;
  
  addItem(item: LibraryItem): void {
    this.items.push(item);
    console.log(`๐Ÿ“š Added: ${item.title}`);
  }
  
  removeItem(itemId: string): boolean {
    const index = this.items.findIndex(item => item.id === itemId);
    if (index !== -1) {
      this.items.splice(index, 1);
      return true;
    }
    return false;
  }
  
  searchItems(query: string): LibraryItem[] {
    const lowerQuery = query.toLowerCase();
    return this.items.filter(item => 
      item.title.toLowerCase().includes(lowerQuery) ||
      (item.type === "book" && item.authors.some(author => 
        author.toLowerCase().includes(lowerQuery)
      ))
    );
  }
  
  registerMember(member: LibraryMember): void {
    this.members.push(member);
    console.log(`๐Ÿ‘ค New member: ${member.name}`);
  }
  
  findMember(memberId: string): LibraryMember | undefined {
    return this.members.find(member => member.id === memberId);
  }
  
  borrowItem(memberId: string, itemId: string): BorrowingRecord {
    const member = this.findMember(memberId);
    const item = this.items.find(i => i.id === itemId);
    
    if (!member || !item || !item.available) {
      throw new Error("Cannot borrow item");
    }
    
    const record: BorrowingRecord = {
      id: `BR-${Date.now()}`,
      memberId,
      itemId,
      borrowDate: new Date(),
      dueDate: new Date(Date.now() + 14 * 24 * 60 * 60 * 1000) // 2 weeks
    };
    
    item.available = false;
    this.borrowingRecords.push(record);
    
    console.log(`โœ… ${member.name} borrowed "${item.title}"`);
    return record;
  }
  
  returnItem(recordId: string): void {
    const record = this.borrowingRecords.find(r => r.id === recordId);
    if (!record) throw new Error("Record not found");
    
    const item = this.items.find(i => i.id === record.itemId);
    if (item) item.available = true;
    
    record.returnDate = new Date();
    record.lateFee = this.calculateLateFee(record);
    
    console.log(`๐Ÿ“– Item returned${record.lateFee > 0 ? ` with $${record.lateFee} late fee` : ''}`);
  }
  
  calculateLateFee(record: BorrowingRecord): number {
    if (!record.returnDate) return 0;
    
    const daysLate = Math.max(0, 
      Math.floor((record.returnDate.getTime() - record.dueDate.getTime()) / (1000 * 60 * 60 * 24))
    );
    
    return daysLate * this.lateFeePerDay;
  }
  
  reserveItem(memberId: string, itemId: string): Reservation {
    const reservation: Reservation = {
      id: `RES-${Date.now()}`,
      memberId,
      itemId,
      reservationDate: new Date(),
      expiryDate: new Date(Date.now() + 7 * 24 * 60 * 60 * 1000), // 1 week
      status: "active"
    };
    
    this.reservations.push(reservation);
    console.log(`๐Ÿ“… Item reserved`);
    return reservation;
  }
  
  cancelReservation(reservationId: string): void {
    const index = this.reservations.findIndex(r => r.id === reservationId);
    if (index !== -1) {
      this.reservations.splice(index, 1);
      console.log(`โŒ Reservation cancelled`);
    }
  }
}

// ๐ŸŽฎ Usage example
const library = new PublicLibrary();

// Add a book
const typeScriptBook: Book = {
  id: "BOOK-001",
  type: "book",
  title: "Learning TypeScript",
  isbn: "978-1-098-11033-8",
  authors: ["Josh Goldberg"],
  publisher: "O'Reilly",
  publishYear: 2022,
  pages: 320,
  genre: ["Programming", "Web Development"],
  available: true,
  location: "Shelf A-15"
};

library.addItem(typeScriptBook);

// Register a member
const student: Student = {
  id: "MEM-001",
  memberType: "student",
  name: "Alice Johnson",
  email: "[email protected]",
  phone: "555-0123",
  memberSince: new Date(),
  isActive: true,
  borrowingLimit: 5,
  studentId: "STU-2024-001",
  school: "Tech University"
};

library.registerMember(student);

// Borrow a book
const borrowing = library.borrowItem(student.id, typeScriptBook.id);
console.log(`Due date: ${borrowing.dueDate.toLocaleDateString()} ๐Ÿ“…`);

๐ŸŽ“ Key Takeaways

Youโ€™ve mastered TypeScript interfaces! Hereโ€™s what you can now do:

  • โœ… Create interfaces to define object shapes ๐Ÿ’ช
  • โœ… Use optional and readonly properties effectively ๐ŸŽฏ
  • โœ… Extend interfaces to build complex types ๐Ÿ—๏ธ
  • โœ… Implement interfaces in classes ๐Ÿ›ก๏ธ
  • โœ… Design better APIs with clear contracts! ๐Ÿš€

Remember: Interfaces are the backbone of TypeScriptโ€™s type system - use them to make your code more predictable and maintainable! ๐Ÿค

๐Ÿค Next Steps

Congratulations! ๐ŸŽ‰ Youโ€™ve unlocked the power of interfaces!

Hereโ€™s what to do next:

  1. ๐Ÿ’ป Complete the library system exercise
  2. ๐Ÿ—๏ธ Refactor existing code to use interfaces
  3. ๐Ÿ“š Learn about generic interfaces
  4. ๐ŸŒŸ Explore type aliases and union types!

Remember: Great software is built on solid contracts. Keep defining those interfaces! ๐Ÿš€

Happy coding! ๐ŸŽ‰๐Ÿš€โœจ