← Back to Course

🏗️ Objects & Interfaces

Objects are central to JavaScript and TypeScript. Interfaces and type aliases let you define the shape of objects, ensuring consistency and catching errors before they happen.

Object Types

You can define object types inline or extract them into reusable interfaces:

Example: Inline Object Types

// Inline object type
function printPlayer(player: { name: string; level: number }) {
  console.log(`${player.name} is level ${player.level}`);
}

printPlayer({ name: "Hero", level: 5 });

// Object type with optional properties
function createUser(config: { 
  username: string; 
  email?: string;  // Optional
  age?: number; 
}) {
  return config;
}

createUser({ username: "alice" });
createUser({ username: "bob", email: "bob@example.com", age: 30 });

Interfaces

Interfaces are the recommended way to define object shapes in TypeScript. They're reusable, extendable, and self-documenting:

Example: Interface Definitions

// Define an interface
interface Player {
  name: string;
  health: number;
  level: number;
  isAlive: boolean;
}

// Use the interface
const hero: Player = {
  name: "Aragon",
  health: 100,
  level: 5,
  isAlive: true
};

// Function using interface
function healPlayer(player: Player, amount: number): void {
  player.health += amount;
  console.log(`${player.name} healed for ${amount} HP`);
}

healPlayer(hero, 25);

Optional and Readonly Properties

Interfaces support optional properties (?) and readonly properties:

Example: Optional and Readonly

interface GameConfig {
  readonly maxPlayers: number;  // Cannot be changed after creation
  difficulty: string;
  soundEnabled?: boolean;       // Optional property
  musicVolume?: number;         // Optional property
}

const config: GameConfig = {
  maxPlayers: 4,
  difficulty: "normal"
};

// config.maxPlayers = 8;  // ✗ Error: Cannot assign to 'maxPlayers'
config.difficulty = "hard"; // ✓ OK

// Optional properties can be undefined
if (config.soundEnabled === undefined) {
  config.soundEnabled = true;
}

Interface Extension

Interfaces can extend other interfaces, creating hierarchies:

Example: Extending Interfaces

// Base interface
interface Character {
  name: string;
  health: number;
}

// Extended interface inherits base properties
interface Warrior extends Character {
  weaponType: string;
  armor: number;
}

interface Mage extends Character {
  mana: number;
  spells: string[];
}

const knight: Warrior = {
  name: "Sir Galahad",
  health: 150,
  weaponType: "sword",
  armor: 80
};

const wizard: Mage = {
  name: "Merlin",
  health: 80,
  mana: 200,
  spells: ["fireball", "ice storm"]
};

Type Aliases vs Interfaces

Type aliases can also define object shapes. Choose based on your needs:

Example: Type Aliases

// Type alias (similar to interface)
type Point = {
  x: number;
  y: number;
};

// Type alias can also define unions
type Status = "active" | "inactive" | "pending";

// Type alias for function signature
type ClickHandler = (event: MouseEvent) => void;

// When to use interfaces vs type aliases:
// - Use INTERFACE for object shapes (extendable, better error messages)
// - Use TYPE for unions, intersections, and complex types

// Intersection with type aliases
type Named = { name: string };
type Aged = { age: number };
type Person = Named & Aged;  // Combines both types

const person: Person = {
  name: "Alice",
  age: 30
};

Methods in Interfaces

Interfaces can include method signatures:

Example: Interface Methods

interface Inventory {
  items: string[];
  capacity: number;
  
  // Method signatures
  addItem(item: string): boolean;
  removeItem(item: string): boolean;
  isFull(): boolean;
}

// Implementing the interface
class PlayerInventory implements Inventory {
  items: string[] = [];
  capacity: number = 20;
  
  addItem(item: string): boolean {
    if (this.items.length < this.capacity) {
      this.items.push(item);
      return true;
    }
    return false;
  }
  
  removeItem(item: string): boolean {
    const index = this.items.indexOf(item);
    if (index > -1) {
      this.items.splice(index, 1);
      return true;
    }
    return false;
  }
  
  isFull(): boolean {
    return this.items.length >= this.capacity;
  }
}

const backpack = new PlayerInventory();
backpack.addItem("sword");
backpack.addItem("potion");

🎯 Key Concepts

  • Interfaces define the structure (shape) of objects
  • Use ? for optional properties
  • Use readonly for properties that shouldn't change
  • Interfaces can extend other interfaces for code reuse
  • Prefer interfaces for object types, type aliases for unions/intersections
  • Interfaces can include method signatures
  • Classes can implement interfaces to ensure they match a structure
← Back to Beginner Course