+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Part 41 of 355

๐Ÿ— ๏ธ Extending Interfaces: Building Complex Types

Master interface extension in TypeScript to create powerful type hierarchies and compose complex type structures ๐Ÿš€

๐Ÿš€Intermediate
25 min read

Prerequisites

  • Understanding of basic interfaces ๐Ÿ“
  • Knowledge of TypeScript types ๐Ÿ”
  • Familiarity with object-oriented concepts ๐Ÿ’ป

What you'll learn

  • Master interface extension syntax ๐ŸŽฏ
  • Build complex type hierarchies ๐Ÿ—๏ธ
  • Understand multiple interface extension ๐Ÿ”€
  • Apply interface composition patterns โœจ

๐ŸŽฏ Introduction

Welcome to the architectural world of interface extension! ๐ŸŽ‰ In this guide, weโ€™ll explore how to build complex type structures by extending and composing interfaces, creating powerful and flexible type hierarchies.

Youโ€™ll discover how interface extension is like building with LEGO blocks ๐Ÿงฑ - you start with basic pieces and combine them to create magnificent structures. Whether youโ€™re designing API schemas ๐ŸŒ, modeling domain entities ๐Ÿข, or creating component prop hierarchies ๐ŸŽจ, mastering interface extension is crucial for scalable TypeScript applications.

By the end of this tutorial, youโ€™ll be confidently architecting complex type systems that are both powerful and maintainable! Letโ€™s build! ๐ŸŠโ€โ™‚๏ธ

๐Ÿ“š Understanding Interface Extension

๐Ÿค” What is Interface Extension?

Interface extension allows you to build new interfaces based on existing ones, inheriting all their properties and methods. Itโ€™s like evolution in nature ๐Ÿฆ‹ - each generation builds upon the previous one, adding new capabilities while keeping the best features.

In TypeScript, interface extension:

  • โœจ Creates type hierarchies through inheritance
  • ๐Ÿš€ Promotes code reuse and DRY principles
  • ๐Ÿ›ก๏ธ Maintains type safety across inheritance chains
  • ๐Ÿ”ง Enables flexible and composable type design

๐Ÿ’ก Why Extend Interfaces?

Hereโ€™s why developers love interface extension:

  1. Code Reusability โ™ป๏ธ: Donโ€™t repeat yourself
  2. Type Hierarchies ๐Ÿ—๏ธ: Model real-world relationships
  3. Incremental Design ๐Ÿ“ˆ: Build complexity gradually
  4. Maintainability ๐Ÿ”ง: Change base types, update everywhere

Real-world example: Think of a vehicle hierarchy ๐Ÿš—. You start with a basic Vehicle interface, extend it to create Car, Truck, and Motorcycle, each adding specific properties while inheriting common ones like speed and color.

๐Ÿ”ง Basic Interface Extension

๐Ÿ“ Simple Extension Example

Letโ€™s start with a friendly example:

// ๐ŸŽฎ Base character interface
interface Character {
  id: string;
  name: string;
  health: number;
  position: { x: number; y: number };
}

// ๐Ÿฆธ Hero extends Character
interface Hero extends Character {
  level: number;
  experience: number;
  skills: string[];
  mana: number;
}

// ๐Ÿ‘น Enemy extends Character
interface Enemy extends Character {
  damage: number;
  attackSpeed: number;
  loot: string[];
  difficulty: 'easy' | 'medium' | 'hard';
}

// โœ… Create a hero
const warrior: Hero = {
  id: 'hero_001',
  name: 'Aragorn',
  health: 100,
  position: { x: 10, y: 20 },
  level: 15,
  experience: 3500,
  skills: ['Sword Strike', 'Shield Bash', 'Battle Cry'],
  mana: 50
};

// โœ… Create an enemy
const goblin: Enemy = {
  id: 'enemy_042',
  name: 'Sneaky Goblin',
  health: 30,
  position: { x: 50, y: 60 },
  damage: 10,
  attackSpeed: 1.5,
  loot: ['Gold Coin', 'Rusty Dagger'],
  difficulty: 'easy'
};

// ๐ŸŽฏ Function that works with base type
function moveCharacter(character: Character, dx: number, dy: number): void {
  character.position.x += dx;
  character.position.y += dy;
  console.log(`${character.name} moved to (${character.position.x}, ${character.position.y}) ๐Ÿƒ`);
}

// โœจ Works with both Hero and Enemy!
moveCharacter(warrior, 5, 0);
moveCharacter(goblin, -3, 2);

๐Ÿ—๏ธ Building Complex Hierarchies

Letโ€™s create a more elaborate example with multiple levels:

// ๐Ÿข E-commerce type hierarchy
interface Product {
  id: string;
  name: string;
  price: number;
  description: string;
  inStock: boolean;
}

interface PhysicalProduct extends Product {
  weight: number;
  dimensions: {
    length: number;
    width: number;
    height: number;
  };
  shippingCost: number;
}

interface DigitalProduct extends Product {
  downloadUrl: string;
  fileSize: number;
  format: string;
}

// ๐Ÿ“ฑ Electronics extend PhysicalProduct
interface Electronics extends PhysicalProduct {
  brand: string;
  warranty: number; // months
  powerRequirements: string;
}

interface Smartphone extends Electronics {
  screenSize: number;
  camera: {
    megapixels: number;
    features: string[];
  };
  storage: number; // GB
  operatingSystem: 'iOS' | 'Android' | 'Other';
  connectivity: string[];
}

// ๐Ÿ“š Books can be physical or digital
interface Book extends Product {
  author: string;
  isbn: string;
  pages: number;
  genre: string[];
  publisher: string;
}

interface PhysicalBook extends Book, PhysicalProduct {
  coverType: 'hardcover' | 'paperback';
}

interface EBook extends Book, DigitalProduct {
  hasAudioVersion: boolean;
  supportedDevices: string[];
}

// โœ… Create complex products
const iPhone: Smartphone = {
  // Product properties
  id: 'prod_iphone_15',
  name: 'iPhone 15 Pro',
  price: 999,
  description: 'Latest flagship smartphone',
  inStock: true,
  
  // PhysicalProduct properties
  weight: 0.187,
  dimensions: { length: 146.6, width: 70.6, height: 8.25 },
  shippingCost: 9.99,
  
  // Electronics properties
  brand: 'Apple',
  warranty: 12,
  powerRequirements: 'USB-C charging',
  
  // Smartphone specific
  screenSize: 6.1,
  camera: {
    megapixels: 48,
    features: ['Night mode', 'ProRAW', '4K video', 'Macro']
  },
  storage: 256,
  operatingSystem: 'iOS',
  connectivity: ['5G', 'WiFi 6E', 'Bluetooth 5.3', 'NFC']
};

const programmingBook: EBook = {
  // Product properties
  id: 'book_ts_mastery',
  name: 'TypeScript Mastery',
  price: 39.99,
  description: 'Complete guide to TypeScript',
  inStock: true,
  
  // Book properties
  author: 'John Doe',
  isbn: '978-1234567890',
  pages: 450,
  genre: ['Programming', 'Technology', 'Education'],
  publisher: 'Tech Press',
  
  // DigitalProduct properties
  downloadUrl: 'https://downloads.example.com/ts-mastery.pdf',
  fileSize: 15.5, // MB
  format: 'PDF',
  
  // EBook specific
  hasAudioVersion: true,
  supportedDevices: ['Kindle', 'iPad', 'Web Reader', 'Android']
};

// ๐ŸŽฏ Functions can work at different hierarchy levels
function calculateShipping(product: PhysicalProduct): number {
  const baseRate = 5;
  const weightRate = product.weight * 2;
  return baseRate + weightRate + product.shippingCost;
}

function applyDiscount(product: Product, percentage: number): number {
  return product.price * (1 - percentage / 100);
}

console.log(`๐Ÿ“ฆ Shipping cost for iPhone: $${calculateShipping(iPhone).toFixed(2)}`);
console.log(`๐Ÿ’ฐ EBook price with 20% discount: $${applyDiscount(programmingBook, 20).toFixed(2)}`);

๐Ÿ”€ Multiple Interface Extension

๐ŸŒŸ Extending Multiple Interfaces

TypeScript allows extending multiple interfaces, combining their properties:

// ๐ŸŽฏ Multiple interface composition
interface Timestamped {
  createdAt: Date;
  updatedAt: Date;
}

interface Identifiable {
  id: string;
  uuid: string;
}

interface Versioned {
  version: number;
  previousVersions: number[];
}

interface Auditable {
  createdBy: string;
  lastModifiedBy: string;
  changeLog: Array<{
    timestamp: Date;
    user: string;
    changes: string;
  }>;
}

// ๐Ÿ“„ Document combines multiple interfaces
interface Document extends Identifiable, Timestamped, Versioned, Auditable {
  title: string;
  content: string;
  tags: string[];
  status: 'draft' | 'review' | 'published' | 'archived';
}

// ๐Ÿ‘ค User profile with multiple concerns
interface ContactInfo {
  email: string;
  phone?: string;
  address?: {
    street: string;
    city: string;
    country: string;
    postalCode: string;
  };
}

interface SocialMedia {
  twitter?: string;
  linkedin?: string;
  github?: string;
  website?: string;
}

interface Preferences {
  theme: 'light' | 'dark' | 'auto';
  language: string;
  notifications: {
    email: boolean;
    push: boolean;
    sms: boolean;
  };
}

interface UserProfile extends Identifiable, Timestamped, ContactInfo, SocialMedia, Preferences {
  username: string;
  displayName: string;
  bio: string;
  avatar: string;
  role: 'user' | 'admin' | 'moderator';
  isVerified: boolean;
}

// โœ… Create a comprehensive user profile
const userProfile: UserProfile = {
  // Identifiable
  id: 'usr_123',
  uuid: '550e8400-e29b-41d4-a716-446655440000',
  
  // Timestamped
  createdAt: new Date('2024-01-01'),
  updatedAt: new Date('2024-06-18'),
  
  // ContactInfo
  email: '[email protected]',
  phone: '+1-555-0123',
  address: {
    street: '123 TypeScript Lane',
    city: 'Code City',
    country: 'Developerland',
    postalCode: '12345'
  },
  
  // SocialMedia
  twitter: '@johndoe',
  github: 'johndoe',
  linkedin: 'john-doe',
  website: 'https://johndoe.dev',
  
  // Preferences
  theme: 'dark',
  language: 'en-US',
  notifications: {
    email: true,
    push: true,
    sms: false
  },
  
  // UserProfile specific
  username: 'johndoe',
  displayName: 'John Doe',
  bio: 'TypeScript enthusiast and software architect',
  avatar: 'https://avatars.example.com/johndoe.jpg',
  role: 'admin',
  isVerified: true
};

// ๐Ÿช E-commerce order combining multiple concerns
interface PricingInfo {
  subtotal: number;
  tax: number;
  shipping: number;
  discount: number;
  total: number;
}

interface PaymentInfo {
  method: 'credit_card' | 'paypal' | 'crypto' | 'bank_transfer';
  status: 'pending' | 'processing' | 'completed' | 'failed';
  transactionId?: string;
  paidAt?: Date;
}

interface ShippingInfo {
  carrier: string;
  trackingNumber?: string;
  estimatedDelivery: Date;
  shippingAddress: {
    recipient: string;
    street: string;
    city: string;
    state: string;
    postalCode: string;
    country: string;
  };
}

interface Order extends Identifiable, Timestamped, PricingInfo, PaymentInfo, ShippingInfo {
  customerId: string;
  items: Array<{
    productId: string;
    quantity: number;
    price: number;
  }>;
  status: 'pending' | 'confirmed' | 'shipped' | 'delivered' | 'cancelled';
  notes?: string;
}

๐ŸŽจ Advanced Extension Patterns

๐Ÿ”ง Generic Interface Extension

Combine generics with extension for ultimate flexibility:

// ๐ŸŽฏ Generic base interfaces
interface Entity<T> {
  id: T;
  metadata: Record<string, any>;
}

interface Timestamped {
  createdAt: Date;
  updatedAt: Date;
}

interface Deletable {
  deletedAt?: Date;
  isDeleted: boolean;
}

// ๐Ÿ“Š Generic repository pattern
interface Repository<T, ID = string> {
  findById(id: ID): Promise<T | null>;
  findAll(): Promise<T[]>;
  save(entity: T): Promise<T>;
  delete(id: ID): Promise<void>;
}

interface CrudRepository<T extends Entity<ID>, ID = string> extends Repository<T, ID> {
  update(id: ID, partial: Partial<T>): Promise<T>;
  exists(id: ID): Promise<boolean>;
  count(): Promise<number>;
}

interface TimestampedRepository<T extends Entity<ID> & Timestamped, ID = string> 
  extends CrudRepository<T, ID> {
  findByDateRange(start: Date, end: Date): Promise<T[]>;
  findRecentlyUpdated(limit: number): Promise<T[]>;
}

interface SoftDeleteRepository<T extends Entity<ID> & Deletable, ID = string>
  extends CrudRepository<T, ID> {
  softDelete(id: ID): Promise<void>;
  restore(id: ID): Promise<void>;
  findDeleted(): Promise<T[]>;
  permanentlyDelete(id: ID): Promise<void>;
}

// ๐Ÿข Domain entity
interface User extends Entity<string>, Timestamped, Deletable {
  email: string;
  username: string;
  passwordHash: string;
  roles: string[];
}

// ๐Ÿ”ง Specialized user repository
interface UserRepository extends TimestampedRepository<User>, SoftDeleteRepository<User> {
  findByEmail(email: string): Promise<User | null>;
  findByUsername(username: string): Promise<User | null>;
  findByRole(role: string): Promise<User[]>;
  updateLastLogin(userId: string): Promise<void>;
}

// โœ… Implementation example
class MongoUserRepository implements UserRepository {
  async findById(id: string): Promise<User | null> {
    console.log(`๐Ÿ” Finding user by ID: ${id}`);
    // MongoDB implementation
    return null;
  }

  async findAll(): Promise<User[]> {
    console.log('๐Ÿ“‹ Finding all users');
    return [];
  }

  async save(user: User): Promise<User> {
    console.log(`๐Ÿ’พ Saving user: ${user.username}`);
    return user;
  }

  async delete(id: string): Promise<void> {
    console.log(`๐Ÿ—‘๏ธ Deleting user: ${id}`);
  }

  async update(id: string, partial: Partial<User>): Promise<User> {
    console.log(`๐Ÿ“ Updating user: ${id}`);
    // Implementation
    return {} as User;
  }

  async exists(id: string): Promise<boolean> {
    console.log(`โ“ Checking if user exists: ${id}`);
    return true;
  }

  async count(): Promise<number> {
    console.log('๐Ÿ”ข Counting users');
    return 42;
  }

  async findByDateRange(start: Date, end: Date): Promise<User[]> {
    console.log(`๐Ÿ“… Finding users between ${start} and ${end}`);
    return [];
  }

  async findRecentlyUpdated(limit: number): Promise<User[]> {
    console.log(`๐Ÿ• Finding ${limit} recently updated users`);
    return [];
  }

  async softDelete(id: string): Promise<void> {
    console.log(`๐Ÿ—‘๏ธ Soft deleting user: ${id}`);
  }

  async restore(id: string): Promise<void> {
    console.log(`โ™ป๏ธ Restoring user: ${id}`);
  }

  async findDeleted(): Promise<User[]> {
    console.log('๐Ÿ—‘๏ธ Finding deleted users');
    return [];
  }

  async permanentlyDelete(id: string): Promise<void> {
    console.log(`๐Ÿ’€ Permanently deleting user: ${id}`);
  }

  async findByEmail(email: string): Promise<User | null> {
    console.log(`๐Ÿ“ง Finding user by email: ${email}`);
    return null;
  }

  async findByUsername(username: string): Promise<User | null> {
    console.log(`๐Ÿ‘ค Finding user by username: ${username}`);
    return null;
  }

  async findByRole(role: string): Promise<User[]> {
    console.log(`๐Ÿ‘ฅ Finding users with role: ${role}`);
    return [];
  }

  async updateLastLogin(userId: string): Promise<void> {
    console.log(`๐Ÿ• Updating last login for user: ${userId}`);
  }
}

๐ŸŒŸ Interface Merging with Extension

TypeScript allows declaration merging with extended interfaces:

// ๐ŸŽฎ Game system with extensible interfaces
interface GameEvent {
  id: string;
  timestamp: Date;
  playerId: string;
}

interface GameEvent {
  // This gets merged with the above!
  eventType: string;
  data: unknown;
}

interface DamageEvent extends GameEvent {
  eventType: 'damage';
  data: {
    targetId: string;
    amount: number;
    damageType: 'physical' | 'magical' | 'true';
    isCritical: boolean;
  };
}

interface ItemEvent extends GameEvent {
  eventType: 'item_pickup' | 'item_drop' | 'item_use';
  data: {
    itemId: string;
    quantity: number;
    location: { x: number; y: number; z: number };
  };
}

interface QuestEvent extends GameEvent {
  eventType: 'quest_start' | 'quest_complete' | 'quest_fail';
  data: {
    questId: string;
    objectives: string[];
    rewards?: {
      experience: number;
      items: string[];
      currency: number;
    };
  };
}

// ๐Ÿญ Event factory
class GameEventFactory {
  private eventCounter = 0;

  createDamageEvent(
    playerId: string,
    targetId: string,
    amount: number,
    damageType: 'physical' | 'magical' | 'true' = 'physical'
  ): DamageEvent {
    return {
      id: `evt_${++this.eventCounter}`,
      timestamp: new Date(),
      playerId,
      eventType: 'damage',
      data: {
        targetId,
        amount,
        damageType,
        isCritical: Math.random() > 0.8
      }
    };
  }

  createItemEvent(
    playerId: string,
    type: 'item_pickup' | 'item_drop' | 'item_use',
    itemId: string,
    quantity: number,
    location: { x: number; y: number; z: number }
  ): ItemEvent {
    return {
      id: `evt_${++this.eventCounter}`,
      timestamp: new Date(),
      playerId,
      eventType: type,
      data: { itemId, quantity, location }
    };
  }

  createQuestEvent(
    playerId: string,
    type: 'quest_start' | 'quest_complete' | 'quest_fail',
    questId: string,
    objectives: string[],
    rewards?: QuestEvent['data']['rewards']
  ): QuestEvent {
    return {
      id: `evt_${++this.eventCounter}`,
      timestamp: new Date(),
      playerId,
      eventType: type,
      data: { questId, objectives, rewards }
    };
  }
}

// ๐ŸŽฏ Event processing
function processGameEvent(event: GameEvent): void {
  console.log(`โšก Processing ${event.eventType} event for player ${event.playerId}`);
  
  switch (event.eventType) {
    case 'damage':
      const damageEvent = event as DamageEvent;
      console.log(`๐Ÿ’ฅ ${damageEvent.data.amount} ${damageEvent.data.damageType} damage!`);
      break;
    
    case 'item_pickup':
      const itemEvent = event as ItemEvent;
      console.log(`๐Ÿ“ฆ Picked up ${itemEvent.data.quantity}x item ${itemEvent.data.itemId}`);
      break;
    
    case 'quest_complete':
      const questEvent = event as QuestEvent;
      console.log(`๐ŸŽ‰ Quest ${questEvent.data.questId} completed!`);
      if (questEvent.data.rewards) {
        console.log(`๐ŸŽ Rewards: ${questEvent.data.rewards.experience} XP`);
      }
      break;
  }
}

โš ๏ธ Common Pitfalls and Solutions

๐Ÿ˜ฑ Pitfall 1: Property Name Conflicts

// โŒ Wrong - conflicting property types
interface Animal {
  name: string;
  age: number;
}

interface Robot {
  name: string;
  age: string; // Different type!
}

// Error: Interface 'Cyborg' cannot simultaneously extend types 'Animal' and 'Robot'
// interface Cyborg extends Animal, Robot {
//   batteryLevel: number;
// }

// โœ… Solution 1: Use compatible types
interface Animal2 {
  name: string;
  biologicalAge: number;
}

interface Robot2 {
  name: string;
  manufacturingDate: string;
}

interface Cyborg extends Animal2, Robot2 {
  batteryLevel: number;
}

// โœ… Solution 2: Use intersection types for conflicts
type CyborgType = Animal & Robot & {
  batteryLevel: number;
  age: number | string; // Explicitly handle the conflict
};

๐Ÿคฏ Pitfall 2: Deep Extension Chains

// โŒ Wrong - too deep inheritance
interface A { a: string; }
interface B extends A { b: string; }
interface C extends B { c: string; }
interface D extends C { d: string; }
interface E extends D { e: string; }
interface F extends E { f: string; }
// This gets hard to maintain!

// โœ… Better - use composition
interface BaseProps {
  id: string;
  timestamp: Date;
}

interface UserProps {
  username: string;
  email: string;
}

interface ProfileProps {
  bio: string;
  avatar: string;
}

interface AdminProps {
  permissions: string[];
  adminLevel: number;
}

// Compose what you need
interface AdminUser extends BaseProps, UserProps, ProfileProps, AdminProps {
  lastAdminAction: Date;
}

๐Ÿ”„ Pitfall 3: Circular Dependencies

// โŒ Wrong - circular reference
// interface Parent extends Child { // Error!
//   children: Child[];
// }

// interface Child extends Parent {
//   parent: Parent;
// }

// โœ… Correct - use proper hierarchy
interface Person {
  id: string;
  name: string;
}

interface Parent extends Person {
  children: Child[];
}

interface Child extends Person {
  parents: Parent[];
  school?: string;
}

๐Ÿ› ๏ธ Best Practices

๐ŸŽฏ Extension Guidelines

  1. Keep It Shallow ๐Ÿ“: Avoid deep inheritance chains
  2. Compose, Donโ€™t Inherit ๐Ÿงฉ: Prefer composition for flexibility
  3. Single Responsibility ๐ŸŽฏ: Each interface should have one purpose
  4. Meaningful Names ๐Ÿ“: Use descriptive interface names
// ๐ŸŒŸ Good practices example
interface Identifiable {
  id: string;
}

interface Trackable {
  createdAt: Date;
  updatedAt: Date;
  createdBy: string;
  updatedBy: string;
}

interface Publishable {
  publishedAt?: Date;
  isPublished: boolean;
  publishedBy?: string;
}

interface SEO {
  metaTitle: string;
  metaDescription: string;
  keywords: string[];
  canonicalUrl?: string;
}

// ๐Ÿ“ Blog post combining concerns
interface BlogPost extends Identifiable, Trackable, Publishable, SEO {
  title: string;
  slug: string;
  content: string;
  excerpt: string;
  featuredImage?: string;
  category: string;
  tags: string[];
  readTime: number;
  viewCount: number;
}

// ๐ŸŽฏ Clear, composable, maintainable!

๐Ÿงช Hands-On Exercise

๐ŸŽฏ Challenge: Build a Component System

Create a flexible UI component type system using interface extension:

๐Ÿ“‹ Requirements:

  • โœ… Base component interface with common props
  • ๐ŸŽจ Styled component extension
  • ๐ŸŽฏ Interactive component extension
  • ๐Ÿ“Š Form component hierarchy
  • ๐Ÿ”ง Composite component patterns

๐Ÿš€ Bonus Points:

  • Add generic type parameters
  • Implement event handling interfaces
  • Create specialized input components

๐Ÿ’ก Solution

๐Ÿ” Click to see solution
// ๐ŸŽฏ Base component interfaces
interface BaseComponent {
  id?: string;
  className?: string;
  testId?: string;
  'aria-label'?: string;
}

interface StyledComponent {
  style?: React.CSSProperties;
  theme?: 'light' | 'dark' | 'auto';
  variant?: string;
  size?: 'small' | 'medium' | 'large';
}

interface InteractiveComponent {
  disabled?: boolean;
  loading?: boolean;
  tabIndex?: number;
  role?: string;
}

// ๐ŸŽจ Layout components
interface LayoutComponent extends BaseComponent, StyledComponent {
  children?: React.ReactNode;
  padding?: string | number;
  margin?: string | number;
}

interface FlexContainer extends LayoutComponent {
  direction?: 'row' | 'column';
  justify?: 'start' | 'center' | 'end' | 'space-between' | 'space-around';
  align?: 'start' | 'center' | 'end' | 'stretch';
  gap?: string | number;
  wrap?: boolean;
}

interface GridContainer extends LayoutComponent {
  columns?: number | string;
  rows?: number | string;
  gap?: string | number;
  areas?: string[];
}

// ๐Ÿ”˜ Button hierarchy
interface ButtonBase extends BaseComponent, StyledComponent, InteractiveComponent {
  children: React.ReactNode;
  onClick?: (event: React.MouseEvent<HTMLButtonElement>) => void;
  type?: 'button' | 'submit' | 'reset';
}

interface IconButton extends ButtonBase {
  icon: React.ReactNode;
  iconPosition?: 'left' | 'right';
  children?: never; // Icon buttons don't have text children
  tooltip?: string;
}

interface ActionButton extends ButtonBase {
  variant: 'primary' | 'secondary' | 'danger' | 'success' | 'warning';
  fullWidth?: boolean;
  icon?: React.ReactNode;
  iconPosition?: 'left' | 'right';
}

interface ToggleButton extends ButtonBase {
  pressed: boolean;
  onToggle: (pressed: boolean) => void;
  'aria-pressed': boolean;
}

// ๐Ÿ“ Form components
interface FormField<T = string> extends BaseComponent, InteractiveComponent {
  name: string;
  value: T;
  onChange: (value: T) => void;
  error?: string;
  required?: boolean;
  label?: string;
  hint?: string;
}

interface TextInput extends FormField<string> {
  type?: 'text' | 'email' | 'password' | 'tel' | 'url';
  placeholder?: string;
  maxLength?: number;
  pattern?: string;
  autoComplete?: string;
}

interface NumberInput extends FormField<number> {
  min?: number;
  max?: number;
  step?: number;
  placeholder?: string;
}

interface SelectInput<T = string> extends FormField<T> {
  options: Array<{
    value: T;
    label: string;
    disabled?: boolean;
    group?: string;
  }>;
  placeholder?: string;
  multiple?: boolean;
}

interface CheckboxInput extends FormField<boolean> {
  indeterminate?: boolean;
  children: React.ReactNode;
}

interface RadioGroup<T = string> extends FormField<T> {
  options: Array<{
    value: T;
    label: string;
    disabled?: boolean;
  }>;
  orientation?: 'horizontal' | 'vertical';
}

interface DatePicker extends FormField<Date | null> {
  minDate?: Date;
  maxDate?: Date;
  disabledDates?: Date[];
  format?: string;
  showTime?: boolean;
}

// ๐ŸŽฏ Complex form component
interface Form extends BaseComponent {
  onSubmit: (values: Record<string, any>) => void | Promise<void>;
  onReset?: () => void;
  children: React.ReactNode;
  validationSchema?: any;
  initialValues?: Record<string, any>;
}

interface FormSection extends BaseComponent {
  title?: string;
  description?: string;
  collapsible?: boolean;
  defaultCollapsed?: boolean;
  children: React.ReactNode;
}

// ๐Ÿ“Š Data display components
interface TableColumn<T> {
  key: keyof T | string;
  header: string;
  render?: (value: any, row: T) => React.ReactNode;
  sortable?: boolean;
  width?: string | number;
  align?: 'left' | 'center' | 'right';
}

interface Table<T> extends BaseComponent, StyledComponent {
  data: T[];
  columns: TableColumn<T>[];
  onRowClick?: (row: T) => void;
  selectable?: boolean;
  onSelectionChange?: (selected: T[]) => void;
  loading?: boolean;
  emptyMessage?: string;
  pagination?: {
    page: number;
    pageSize: number;
    total: number;
    onPageChange: (page: number) => void;
  };
}

// ๐Ÿ”ง Composite component example
interface Card extends LayoutComponent, InteractiveComponent {
  hoverable?: boolean;
  onClick?: () => void;
}

interface CardHeader extends BaseComponent {
  title: string;
  subtitle?: string;
  action?: React.ReactNode;
  avatar?: React.ReactNode;
}

interface CardBody extends LayoutComponent {
  scrollable?: boolean;
  maxHeight?: string | number;
}

interface CardFooter extends LayoutComponent {
  actions?: React.ReactNode[];
  align?: 'left' | 'center' | 'right';
}

// ๐ŸŽจ Modal/Dialog components
interface Modal extends BaseComponent {
  open: boolean;
  onClose: () => void;
  title?: string;
  size?: 'small' | 'medium' | 'large' | 'fullscreen';
  closeOnEscape?: boolean;
  closeOnBackdropClick?: boolean;
  showCloseButton?: boolean;
}

interface ConfirmDialog extends Modal {
  message: string;
  confirmText?: string;
  cancelText?: string;
  onConfirm: () => void | Promise<void>;
  onCancel?: () => void;
  variant?: 'info' | 'warning' | 'danger';
}

// ๐Ÿš€ Implementation example
const MyAwesomeForm: React.FC = () => {
  const handleSubmit = (values: Record<string, any>) => {
    console.log('๐Ÿ“ Form submitted:', values);
  };

  return (
    <Form 
      id="user-registration"
      onSubmit={handleSubmit}
      className="registration-form"
    >
      <FormSection title="Personal Information" description="Tell us about yourself">
        <FlexContainer direction="column" gap={16}>
          <TextInput
            name="fullName"
            label="Full Name"
            value=""
            onChange={(value) => console.log('Name:', value)}
            required
            placeholder="John Doe"
          />
          
          <TextInput
            name="email"
            label="Email"
            type="email"
            value=""
            onChange={(value) => console.log('Email:', value)}
            required
            error="Please enter a valid email"
          />
          
          <DatePicker
            name="birthDate"
            label="Date of Birth"
            value={null}
            onChange={(value) => console.log('Birth date:', value)}
            maxDate={new Date()}
          />
        </FlexContainer>
      </FormSection>
      
      <FormSection title="Preferences" collapsible defaultCollapsed>
        <RadioGroup
          name="theme"
          label="Preferred Theme"
          value="light"
          options={[
            { value: 'light', label: 'โ˜€๏ธ Light' },
            { value: 'dark', label: '๐ŸŒ™ Dark' },
            { value: 'auto', label: '๐Ÿค– Auto' }
          ]}
          onChange={(value) => console.log('Theme:', value)}
          orientation="horizontal"
        />
        
        <CheckboxInput
          name="newsletter"
          value={false}
          onChange={(value) => console.log('Newsletter:', value)}
        >
          Subscribe to our newsletter
        </CheckboxInput>
      </FormSection>
      
      <FlexContainer justify="end" gap={8} margin="16px 0 0 0">
        <ActionButton 
          variant="secondary" 
          type="reset"
          onClick={() => console.log('Form reset')}
        >
          Cancel
        </ActionButton>
        
        <ActionButton 
          variant="primary" 
          type="submit"
          icon={<span>โœ…</span>}
        >
          Register
        </ActionButton>
      </FlexContainer>
    </Form>
  );
};

// ๐Ÿ—๏ธ Type-safe component factory
class ComponentFactory {
  static createButton<T extends ButtonBase>(
    type: 'action' | 'icon' | 'toggle',
    props: T
  ): T {
    console.log(`๐Ÿ”จ Creating ${type} button`);
    return {
      ...props,
      'aria-label': props['aria-label'] || props.children?.toString()
    };
  }

  static createFormField<T extends FormField>(
    fieldType: string,
    props: Omit<T, 'onChange'> & { onChange?: (value: any) => void }
  ): T {
    const fieldProps = {
      ...props,
      onChange: props.onChange || (() => {}),
      'aria-required': props.required,
      'aria-invalid': !!props.error
    };
    
    console.log(`๐Ÿ“‹ Creating ${fieldType} field: ${props.name}`);
    return fieldProps as T;
  }
}

// Usage
const submitButton = ComponentFactory.createButton('action', {
  variant: 'primary',
  children: 'Submit',
  onClick: () => console.log('Submitted!'),
  size: 'large'
} as ActionButton);

const emailField = ComponentFactory.createFormField('text', {
  name: 'email',
  type: 'email',
  label: 'Email Address',
  value: '',
  required: true,
  placeholder: '[email protected]'
} as TextInput);

๐ŸŽ“ Key Takeaways

You now understand how to build complex type hierarchies with interface extension! Hereโ€™s what youโ€™ve learned:

  • โœ… Single extension creates simple hierarchies ๐ŸŽฏ
  • โœ… Multiple extension combines interfaces powerfully ๐Ÿ”€
  • โœ… Generic extension provides ultimate flexibility ๐Ÿงฌ
  • โœ… Composition patterns keep code maintainable ๐Ÿงฉ
  • โœ… Interface merging extends existing types ๐Ÿ”„

Remember: Good interface design is like good architecture - it should be solid, flexible, and beautiful! ๐Ÿ—๏ธ

๐Ÿค Next Steps

Congratulations! ๐ŸŽ‰ Youโ€™ve mastered interface extension in TypeScript!

Hereโ€™s what to do next:

  1. ๐Ÿ’ป Practice with the component system exercise above
  2. ๐Ÿ—๏ธ Refactor existing code to use interface extension
  3. ๐Ÿ“š Move on to our next tutorial: Implementing Multiple Interfaces: Composition over Inheritance
  4. ๐ŸŒŸ Build your own type hierarchies for real projects!

Remember: The best type systems grow organically through thoughtful extension and composition. Keep building! ๐Ÿš€


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