🔥 0
0
Lesson 3 of 10 25 min +125 XP

Interfaces: Defining Shapes

In e-commerce, you deal with complex data: products, carts, orders, customers. Interfaces define what shape that data should have.

Your First Interface

interface Product {
  id: string;
  name: string;
  price: number;
  inStock: boolean;
}

// Now TypeScript enforces this shape
const headphones: Product = {
  id: "SKU-001",
  name: "Wireless Headphones",
  price: 79.99,
  inStock: true
};

// ❌ Error: Missing 'inStock' property
const keyboard: Product = {
  id: "SKU-002",
  name: "Mechanical Keyboard",
  price: 149.99
};

// ❌ Error: 'cost' doesn't exist, did you mean 'price'?
const mouse: Product = {
  id: "SKU-003",
  name: "Gaming Mouse",
  cost: 59.99,  // Wrong property name!
  inStock: true
};

Optional Properties

Not every product has every field. Use ? for optional properties.

interface Product {
  id: string;
  name: string;
  price: number;
  inStock: boolean;
  description?: string;      // Optional
  discountPercent?: number;  // Optional
  imageUrl?: string;         // Optional
}

// Valid - optional fields can be omitted
const basicProduct: Product = {
  id: "SKU-001",
  name: "USB Cable",
  price: 9.99,
  inStock: true
};

// Also valid - with optional fields
const featuredProduct: Product = {
  id: "SKU-002",
  name: "4K Monitor",
  price: 399.99,
  inStock: true,
  description: "Ultra-wide 32 inch display",
  discountPercent: 15,
  imageUrl: "/images/monitor.jpg"
};

Readonly Properties

Some properties shouldn't change after creation.

interface Order {
  readonly orderId: string;      // Can't change after creation
  readonly createdAt: Date;      // Can't change after creation
  items: CartItem[];             // Can be modified
  status: string;                // Can be modified
}

const order: Order = {
  orderId: "ORD-12345",
  createdAt: new Date(),
  items: [],
  status: "pending"
};

order.status = "shipped";     // ✅ OK
order.orderId = "ORD-99999";  // ❌ Error: Cannot assign to 'orderId' because it is read-only

---

Nested Interfaces

Real data is nested. Interfaces can reference other interfaces.

interface Address {
  street: string;
  city: string;
  state: string;
  zipCode: string;
  country: string;
}

interface Customer {
  id: string;
  email: string;
  name: string;
  shippingAddress: Address;   // Nested interface
  billingAddress?: Address;   // Optional nested interface
}

const customer: Customer = {
  id: "CUST-001",
  email: "sarah@example.com",
  name: "Sarah Johnson",
  shippingAddress: {
    street: "123 Main St",
    city: "San Francisco",
    state: "CA",
    zipCode: "94102",
    country: "USA"
  }
  // billingAddress omitted - will use shipping address
};

---

Extending Interfaces

Build on existing interfaces to avoid repetition.

// Base product
interface Product {
  id: string;
  name: string;
  price: number;
}

// Physical product adds shipping info
interface PhysicalProduct extends Product {
  weight: number;       // in kg
  dimensions: {
    width: number;
    height: number;
    depth: number;
  };
}

// Digital product adds download info
interface DigitalProduct extends Product {
  downloadUrl: string;
  fileSizeMB: number;
}

const laptop: PhysicalProduct = {
  id: "SKU-001",
  name: "MacBook Pro",
  price: 1999,
  weight: 1.4,
  dimensions: { width: 31, height: 1.6, depth: 22 }
};

const ebook: DigitalProduct = {
  id: "SKU-002",
  name: "TypeScript Handbook",
  price: 29,
  downloadUrl: "/downloads/ts-handbook.pdf",
  fileSizeMB: 15
};

---

Interface vs Type Alias

Both can define object shapes. Here's when to use each:

// Interface - preferred for objects
interface Product {
  name: string;
  price: number;
}

// Type alias - same result
type ProductType = {
  name: string;
  price: number;
};

Key Differences

FeatureInterfaceType Alias
Extend/Inheritextends& intersection
Merge declarationsYesNo
Union typesNoYes
PrimitivesNoYes
Rule of thumb: Use interface for objects, type for unions and primitives.
// Interface for objects
interface CartItem {
  product: Product;
  quantity: number;
}

// Type for unions (covered next lesson)
type PaymentMethod = "card" | "upi" | "cod";

// Type for computed types
type ProductWithQty = Product & { quantity: number };

---

Building an E-commerce Type System

Let's put it all together:

interface Product {
  id: string;
  name: string;
  price: number;
  category: string;
  inStock: boolean;
  imageUrl?: string;
}

interface CartItem {
  product: Product;
  quantity: number;
}

interface Cart {
  items: CartItem[];
  couponCode?: string;
}

interface Customer {
  id: string;
  email: string;
  name: string;
}

interface Order {
  readonly orderId: string;
  readonly createdAt: Date;
  customer: Customer;
  items: CartItem[];
  shippingAddress: Address;
  status: "pending" | "paid" | "shipped" | "delivered";
  total: number;
}

---

Type Challenges

Challenge 1: Define a Review Interface

Create an interface for product reviews with:

  • id: string
  • productId: string
  • rating: number (1-5)
  • title: string
  • comment: optional string
  • createdAt: Date
  • helpful: number (vote count)
Solution
interface Review {
  id: string;
  productId: string;
  rating: number;
  title: string;
  comment?: string;
  createdAt: Date;
  helpful: number;
}

Challenge 2: Extend the Product

Create a ClothingProduct that extends Product with:

  • size: string
  • color: string
  • material: string
Solution
interface ClothingProduct extends Product {
  size: string;
  color: string;
  material: string;
}

const tshirt: ClothingProduct = {
  id: "SKU-100",
  name: "Cotton T-Shirt",
  price: 24.99,
  category: "clothing",
  inStock: true,
  size: "M",
  color: "Navy Blue",
  material: "100% Cotton"
};

---

Key Takeaways

  • Interfaces define the shape of objects
  • Use ? for optional properties
  • Use readonly for immutable properties
  • Use extends to inherit from other interfaces
  • Prefer interfaces for objects, types for unions

Next up: Arrays & Objects - typing collections of products and complex data structures!

Basic Types