Lesson 2 of 80
Both describe a shape, and for plain object types they're nearly interchangeable — but each can do something the other genuinely cannot.
11 min read
Every option explains itself — why the right one is right, and why each wrong one is wrong. Miss one and it comes back later on a spaced-repetition schedule.
Question 1 of 3
You declare `interface Window { myLibVersion: string }` and later, in a different file, declare `interface Window { featureFlags: Record<string, boolean> }`. What happens?
Hints without spoilers, and a plain explanation of why a wrong answer was wrong — answered only from this lesson. Free account, no card.
Sign up freeWhat interviewers actually ask about this, and what a strong answer has to cover.
A strong answer covers
Likely follow-ups
interface and type both describe a shape, and from the structural typing lesson: TypeScript doesn't care which one you used to describe it — compatibility is about shape either way. For a plain object type, they're nearly interchangeable. The real differences show up at the edges.
interface Point { x: number; y: number }
type PointAlias = { x: number; y: number };
Both work identically here. The differences that actually matter:
interface supports declaration merging — declaring the same interface name twice adds to it, rather than conflicting.type can express things interface cannot — unions, intersections, tuples, primitives, and mapped/conditional types.// some-library's own types.d.ts
interface Window {
myLibVersion: string;
}
// your app's types.d.ts — this ADDS to Window, it doesn't conflict
interface Window {
featureFlags: Record<string, boolean>;
}
// now Window has both properties, merged
window.myLibVersion;
window.featureFlags;
Declaring interface Window a second time doesn't error — it merges. This is exactly how you augment a third-party library's or the global Window's types without editing their source. Try the same thing with type Window = {...} twice, and TypeScript rejects it as a duplicate identifier — type can't be reopened once declared.
interface User { name: string } interface User { age: string } — two declarations MERGE into one.
interface for public object/API shapes that might need extending later (declaration merging is the whole reason to reach for it); use type for unions, tuples, primitives, and anything mapped/conditional.implements works with both, and either way it only checks the shape — a class implements-ing an interface (or a type alias describing an object shape) doesn't create any special runtime coupling, consistent with structural typing from the last lesson."When would you use type over interface?" checks whether you know each one's actual capabilities, not just that they're "basically the same" — the honest answer is that they overlap heavily but aren't redundant, and the difference is what each can express, not a stylistic coin flip.