Core Concepts9 min read · Updated 2025-06-01

TypeScript Types vs Interfaces: The Definitive Guide

A clear, complete comparison of type aliases and interfaces in TypeScript — when to use each, the key differences, and the scenarios where only one works.

💡 Practice these concepts interactively with AI feedback

Start Practicing →

TypeScript Types vs Interfaces: The Definitive Guide

The single most common TypeScript interview question. Here's everything you need to know.

What They Have In Common

Both describe the shape of objects and are structurally equivalent for most everyday use:

// These are identical in usage:
type UserType = { id: number; name: string }
interface UserInterface { id: number; name: string }

function greet(user: UserType) { / works / } function greet(user: UserInterface) { / also works / }

Both can be extended, both appear in IDE tooltips, both enforce structural compatibility.

Key Differences

### 1. Declaration Merging — Interface Only

interface Window {
  myCustomProperty: string
}
interface Window {
  anotherProperty: number
}
// Window now has both properties — merged!

type Config = { debug: boolean } type Config = { verbose: boolean } // ❌ Error: duplicate identifier

This is the killer feature for extending third-party types:

// In your express app: declare module 'express-serve-static-core' {   interface Request {     user?: AuthenticatedUser   } } // Now req.user is typed everywhere

### 2. Union and Intersection — Type Only

type StringOrNumber = string | number           // union
type AdminUser = User & { permissions: string[] } // intersection
type Callback = (err: Error | null) => void    // function type
type Pair<T> = [T, T]                          // tuple

Interfaces cannot express any of these directly.

### 3. Computed / Mapped Types — Type Only

type Keys = keyof User              // 'id' | 'name' | 'email'
type Optional = Partial<User>       // all fields optional
type OnlyIds = Record<string, number>

// Interface cannot do this: type EventHandlers = { [K in keyof Events as on${Capitalize<K>}]: (e: Events[K]) => void }

### 4. Extends vs Intersection

Both can compose types, but differently:

// Interface extends — property conflicts are caught as errors
interface Animal { name: string }
interface Dog extends Animal { breed: string }

// Type intersection — conflicting properties become never type Animal = { name: string; sound: string } type Cat = Animal & { sound: 'meow' } // Cat.sound is 'meow' (intersection narrows it)

Practical Decision Guide

Use interface when:

  • Defining the shape of an object or class contract
  • You need declaration merging (extending third-party modules)
  • Writing a library where consumers may extend types
  • Defining class implements signatures

Use type when:

  • Working with unions or intersections
  • Using mapped types, conditional types, or template literals
  • Defining function signatures (type Fn = (x: string) => void)
  • Creating tuple types
  • Aliasing primitives or utility type results

The Recommended Default

Most style guides say: prefer interface for object shapes, use type for everything else.

The TypeScript team's own guidance: use interface when possible; use type when you need features only type provides.

// Good: interface for object/class shapes
interface Repository<T> {
  findById(id: string): Promise<T>
  save(entity: T): Promise<T>
  delete(id: string): Promise<void>
}

// Good: type for union and complex compositions type Result<T, E extends Error = Error> = | { success: true; data: T } | { success: false; error: E }

One Practical Tip

When in doubt about which to use, start with interface. If TypeScript complains about something interface can't do (unions, mapped types), switch to type. This matches how most TypeScript teams operate in practice.

Practice TypeScript questions at [JSPrep Pro](/auth).

Put This Into Practice

Reading articles is passive. JSPrep Pro makes you actively recall, predict output, and get AI feedback.

Start Free →Browse All Questions

Related Articles

Deep Dive
We Built a RAG-Powered AI Question Engine Into a JavaScript Interview Platform — Here's Exactly How It Works
12 min read
Build Systems
Monorepo with Turborepo vs Nx: The Complete Comparison (2025)
9 min read
Core Concepts
map() vs forEach() in JavaScript: Which One to Use and Why It Matters
7 min read