TypeScript Type vs Interface

Understanding the differences and when to use each

⚖️ Type vs Interface

Both types and interfaces define object shapes in TypeScript, but they have key differences. Interfaces are extendable and better for object-oriented patterns, while types are more flexible for unions, primitives, and complex compositions.


// Interface
interface User {
    name: string;
}

// Type
type Person = {
    name: string;
};
                                    

Key Differences

🔄

Extension

How they extend

// Interface
interface A extends B {}

// Type
type A = B & C;
🔗

Union Types

Only types support unions

// Type only
type ID = 
    string | number;
📝

Declaration Merging

Only interfaces merge

// Interface merges
interface User {
    name: string;
}
interface User {
    age: number;
}
🎯

Primitives

Only types alias primitives

// Type only
type Name = string;
type Count = number;

🔹 Similarities

Both can define object shapes:

// Using Interface
interface UserInterface {
    name: string;
    age: number;
}

// Using Type
type UserType = {
    name: string;
    age: number;
};

let user1: UserInterface = { name: "Alice", age: 25 };
let user2: UserType = { name: "Bob", age: 30 };

console.log(user1.name);
console.log(user2.name);

Output:

Alice

Bob

🔹 Interface Extension

Interfaces use the extends keyword:

interface Animal {
    name: string;
}

interface Dog extends Animal {
    breed: string;
}

let myDog: Dog = {
    name: "Buddy",
    breed: "Labrador"
};

console.log(`${myDog.name} is a ${myDog.breed}`);

Output:

Buddy is a Labrador

🔹 Type Intersection

Types use the & operator to combine:

type Animal = {
    name: string;
};

type Pet = {
    owner: string;
};

type DomesticAnimal = Animal & Pet;

let myCat: DomesticAnimal = {
    name: "Whiskers",
    owner: "Alice"
};

console.log(`${myCat.name} belongs to ${myCat.owner}`);

Output:

Whiskers belongs to Alice

🔹 Union Types (Type Only)

Only types can create unions:

type Status = "success" | "error" | "pending";
type ID = string | number;

let currentStatus: Status = "success";
let userId: ID = 123;
let productId: ID = "prod_456";

console.log(`Status: ${currentStatus}`);
console.log(`User ID: ${userId}`);
console.log(`Product ID: ${productId}`);

Output:

Status: success

User ID: 123

Product ID: prod_456

🔹 Declaration Merging (Interface Only)

Interfaces with the same name automatically merge:

interface Window {
    title: string;
}

interface Window {
    width: number;
}

// Both properties are now available
let myWindow: Window = {
    title: "My App",
    width: 800
};

console.log(`${myWindow.title} - Width: ${myWindow.width}px`);

Output:

My App - Width: 800px

Note: Types cannot be merged. Declaring the same type twice causes an error.

🔹 Primitive Aliases (Type Only)

Only types can alias primitive values:

type Username = string;
type Age = number;
type IsActive = boolean;

let user: Username = "john_doe";
let userAge: Age = 28;
let active: IsActive = true;

console.log(`User: ${user}, Age: ${userAge}, Active: ${active}`);

Output:

User: john_doe, Age: 28, Active: true

🔹 Tuple Types (Type Only)

Types work better with tuples:

type Point = [number, number];
type RGB = [number, number, number];

let coordinate: Point = [10, 20];
let color: RGB = [255, 128, 0];

console.log(`Point: (${coordinate[0]}, ${coordinate[1]})`);
console.log(`Color: rgb(${color.join(", ")})`);

Output:

Point: (10, 20)

Color: rgb(255, 128, 0)

🔹 When to Use Each

Use Interface When:

  • Defining object shapes and contracts
  • Working with classes and OOP patterns
  • You need declaration merging
  • Building public APIs or libraries
  • Extending other interfaces

Use Type When:

  • Creating union or intersection types
  • Aliasing primitives or tuples
  • Using mapped or conditional types
  • Defining complex type compositions
  • Working with utility types

🔹 Practical Comparison

Real-world example showing both:

// Interface for object structure
interface Product {
    id: number;
    name: string;
    price: number;
}

// Type for union and complex types
type PaymentMethod = "credit" | "debit" | "paypal";
type OrderStatus = "pending" | "shipped" | "delivered";

// Combining both
interface Order {
    product: Product;
    payment: PaymentMethod;
    status: OrderStatus;
}

let myOrder: Order = {
    product: { id: 1, name: "Laptop", price: 999 },
    payment: "credit",
    status: "pending"
};

console.log(`Order: ${myOrder.product.name} - ${myOrder.status}`);

Output:

Order: Laptop - pending

🧠 Test Your Knowledge

Which can create union types?