Here's my decision framework after 5 years of TypeScript:
Use interface when:
- Defining the shape of objects or classes
- You want declaration merging (e.g., extending third-party types)
- Building a public API/library (interfaces produce better error messages)
Use type when:
- Union types:
type Status = 'active' | 'inactive'
- Intersection types with non-object types
- Mapped or conditional types:
type Nullable<T> = T | null
- Tuple types:
type Point = [number, number]
For the extending question: both work, but syntactically:
// interface
interface Animal { name: string }
interface Dog extends Animal { breed: string }
// type
type Animal = { name: string }
type Dog = Animal & { breed: string }
They're functionally equivalent for object types. Pick one and be consistent.