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
| Feature | Interface | Type Alias |
|---|---|---|
| Extend/Inherit | extends | & intersection |
| Merge declarations | Yes | No |
| Union types | No | Yes |
| Primitives | No | Yes |
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: stringproductId: stringrating: number (1-5)title: stringcomment: optional stringcreatedAt: Datehelpful: 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: stringcolor: stringmaterial: 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
readonlyfor immutable properties - Use
extendsto inherit from other interfaces - Prefer interfaces for objects, types for unions
Next up: Arrays & Objects - typing collections of products and complex data structures!