CodeOath
← All posts
TypeScript75 min total · 21 parts

TypeScript Fundamentals: Types, Interfaces, Generics, and Why It Catches Bugs Before Runtime

Contents — Part 5 of 21: interface vs. type
Part 5 of 21 · ~1 min

interface vs. type

interface User { name: string; age: number; }
type UserT = { name: string; age: number; };

For plain object shapes, these are nearly interchangeable, and this is one of the most commonly asked "what's the difference" questions in TypeScript interviews. The practical differences:

interfacetype
Object shapesYesYes
Unions ("a" | "b")NoYes
Primitives/tuplesNoYes
Extending another shapeextends& (intersection)
Re-opening after declarationYes — declaration mergingNo — a duplicate name is an error
Typical usePublic object/class contracts meant to be extended or implementedUnions, tuples, primitives, and everything not naturally "object-shaped"

Declaration merging is the one behavioral difference worth knowing in depth: re-declaring an interface with the same name adds to it rather than conflicting.

interface Window {
  myGlobal: string;
}
interface Window {
  anotherGlobal: number;
}
// Window now effectively has both myGlobal and anotherGlobal

This is exactly how libraries let you extend global or third-party types (augmenting express's Request, or the global Window) without forking their source — and exactly why it can bite you by accident if two unrelated files declare an interface with the same name, expecting two separate types, and instead silently get one merged type.