📖 The Story: The Shape Shifter

A team was building a payment gateway. The frontend developer assumed the API response for a transaction looked like this: { amount: number, currency: string }. They wrote transaction.amount.toFixed(2) to display the price.

In production, the API started returning { amount: "100.00", currency: "USD" } because a backend dev decided strings were easier to format. The frontend crashed instantly: toFixed is not a function.

Because they were using plain JavaScript, there was no contract. The data shape shifted without warning. The team immediately adopted TypeScript Interfaces. They defined a Transaction interface. The backend team looked at the interface, realized their mistake, and fixed the API to return a number. The crash never happened again.

Without interfaces, data is a shape-shifting monster. With interfaces, it's a locked box with a clear label.

🎯 Why Interfaces?

📐

Data Contracts

Define exactly what properties an object must have, preventing undefined errors.

📖

Self-Documenting

Hovering over a variable in your IDE instantly shows its shape.

🧩

Composability

Interfaces can be combined and extended to build complex data models.

🧒 Explain Like I'm 10

Imagine you are ordering a Happy Meal. The Happy Meal has a contract: it must come with a burger, fries, a drink, and a toy.

If the cashier hands you a bag with just a burger and fries, you know it's wrong. An Interface is the picture on the menu that shows exactly what should be in the bag. TypeScript is the manager who checks the bag before handing it to you.

🎓 Professional Explanation

An Interface is a way to describe the shape of an object. It acts as a blueprint. Unlike classes, interfaces do not exist at runtime; they are purely for compile-time type checking. TypeScript uses "structural typing", meaning if an object has the properties required by the interface, it is considered compatible, regardless of its name.

⚙️ Defining Interfaces

Here is how you define and use a basic interface:

typescript
// 1. Define the contract
interface User {
  id: number;
  name: string;
  email: string;
}

// 2. Use it
const adminUser: User = {
  id: 1,
  name: "Ram",
  email: "ram@test.com"
};

// Error: Property 'email' is missing.
const guestUser: User = {
  id: 2,
  name: "Guest"
};

🔒 Optional & Readonly Properties

Sometimes a property isn't required, or shouldn't be changed after initialization.

typescript
interface Product {
  // Readonly: Can only be set once
  readonly sku: string;
  name: string;
  price: number;
  
  // Optional: Doesn't have to exist
  description?: string;
}

const laptop: Product = {
  sku: "LP-2025",
  name: "MacBook Pro",
  price: 1999
  // description is omitted, which is valid!
};

laptop.sku = "LP-2026"; // Error: Cannot assign to 'sku' because it is read-only

🔗 Extending Interfaces

Interfaces can inherit from other interfaces, allowing you to build complex models from simple ones.

typescript
interface Animal {
  legs: number;
}

interface Dog extends Animal {
  bark(): void;
}

const myDog: Dog = {
  legs: 4, // Inherited from Animal
  bark() { console.log("Woof!"); }
};

⚔️ Type vs Interface

TypeScript has two ways to define shapes: interface and type. Which should you use?

FeatureInterfaceType Alias
Object Shapes✅ Excellent✅ Excellent
Unions / Primitives❌ Not possibletype ID = string | number
Extendingextends✅ Intersection (&)
Declaration Merging✅ Yes (combines same names)❌ No (errors on duplicate)
💡 Rule of Thumb

Use interface for object shapes and class implementations. Use type for unions, intersections, and utility types.

⚠️ Common Mistakes

Mistake 1: Excess Property Checking

If you pass an object literal directly, TypeScript checks for excess properties.

typescript
interface User { name: string; }

// Error: 'age' does not exist in type 'User'
const u: User = { name: "Ram", age: 30 };

// Valid: Excess properties aren't checked on variables
const rawData = { name: "Ram", age: 30 };
const u2: User = rawData; // OK!

✅ Best Practices

  1. Use PascalCase: Name interfaces like UserProfile, not userProfile.
  2. Don't prefix with 'I': Avoid IUser. TypeScript context makes it clear it's an interface.
  3. Prefer Interfaces for Objects: Reserve type for complex utility types.

🏗️ Senior Deep Dive

Declaration Merging

Interfaces can "merge". If you declare two interfaces with the same name, TypeScript combines them. This is extremely useful for extending third-party library types or augmenting the global Window object.

typescript
interface Window {
  myCustomGlobalVar: string;
}

window.myCustomGlobalVar = "Hello"; // No TS error!

💼 Interview Questions

Beginner
What is the ? used for in an interface?
Show Answer
The ? marks a property as optional. The object is valid whether the property is present or undefined.
Intermediate
What is Declaration Merging?
Show Answer
It is a feature of interfaces where two interfaces with the same name in the same scope are automatically merged into a single interface containing all properties. Types do not support this.

🏋️ Practical Exercise

🎯 Hands-On Practice Easy

Build the Blueprint

Create an interface BlogPost that requires:

  • id (readonly number)
  • title (string)
  • content (string)
  • tags (optional array of strings)

Instantiate a variable using this interface and try to reassign the id to see the error.

📝 Quiz

Test your understanding. Click an option to check your answer.

1. How do you make a property optional in an interface?
A) property?: type
B) property: type?
C) optional property: type
Answer: A — The ? is placed before the colon to denote an optional property.

📦 Summary

🎯 Key Takeaways

  • Interfaces define the shape of objects.
  • Use readonly for immutable properties and ? for optional ones.
  • Interfaces can extend other interfaces.
  • Prefer interface for objects, type for unions/primitives.