Interfaces & Type Aliases
Intermediate · 20 min read · ▶ live playground · ✦ checkpoint
Use type for most app shapes; use interface when you deliberately want an object contract that can be reopened and merged. They overlap so much that beginners hear "it doesn't matter," but the last 10% matters exactly when teams need a rule they can defend.
An object shape is the list of properties and function members a value must have. A type alias is a reusable name for any type, and an interface is a reusable name for an object shape. Both live only in the type layer, so both erase before runtime, just like the interface Rocket block you watched disappear in 1.5.
The 90% overlap
For everyday objects, the two syntaxes describe the same set of allowed values:
type LaunchPlan = {
name: string;
window: string;
};
interface LaunchTicket {
name: string;
window: string;
}
function planLabel(plan: LaunchPlan): string {
return plan.name + " launches at " + plan.window;
}
function ticketLabel(ticket: LaunchTicket): string {
return ticket.name + " checks in at " + ticket.window;
}
console.log(planLabel({ name: "Astra", window: "09:00" }));
console.log(ticketLabel({ name: "Mina", window: "08:30" }));→ Astra launches at 09:00 | Mina checks in at 08:30
Both give the checker a named promise. If window is missing, the object is outside the allowed set. If window is a number, same story. Neither syntax creates a JavaScript constructor, runtime validator, or object factory.
The overlap covers the work you do every day: required properties, optional properties, nested objects, arrays, and function-valued properties. If all you ever wrote were plain object shapes, either syntax could carry the promise.
Where type reaches farther
The reason this course defaults to type is not fashion. A type alias can name object shapes, but it can also name unions, tuples, and function types with the same habit:
An interface can describe object-like things, including callable objects, but it cannot directly name "free" | "pro" or [string, number]. So if your codebase uses interfaces for object shapes, you still need type aliases nearby for the rest of the type language.
That is the first half of the team rule: default to type for app data. It keeps object shapes, unions, tuples, and function types under one spelling.
Declaration merging
Declaration merging means TypeScript combines multiple declarations with the same interface name into one larger interface. Think of an interface as an open signup sheet: another interface User can add a required line later.
interface User {
name: string;
}
interface User {
plan: "free" | "pro";
}
const user: User = { name: "Mina" };→ playground.ts:9:7 - error TS2741: Property 'plan' is missing in type '{ name: string; }' but required in type 'User'.
That merge is a real feature. It lets library-style code publish an interface, then let another declaration add fields to it without editing the original file. You don't need that power often in application data, but when you do, interface is the tool.
The team decision rule
Here is the rule later lessons in this course follow:
- Start with
typefor app data, unions, tuples, and function shapes. - Use
interfacewhen you intentionally want declaration merging. - Don't mix both names for the same domain idea just to express personal taste.
A domain idea is a concept from your product, like a user, plan, launch, or receipt. If type User and interface UserProfile both describe the same product idea, readers now have to ask whether the difference matters. Usually it doesn't. Pick the boring rule and make the code easy to scan.
This rule also keeps future refactors honest. If a type alias is duplicated, the checker complains at the name. If an interface is duplicated, the checker assumes you meant to add to it. Choose the open door only when the open door is the point.
Recursive shapes
A recursive shape is a type whose property refers back to the same type, so it can model trees like comments, folders, and menu items. The idea is not "infinite object." It is one card that says, "each reply follows this same card too."
In the playground, for...of visits each reply, and countComments calls itself when a reply has more replies nested inside it.
Interfaces can be recursive too:
interface MenuItem {
label: string;
children: MenuItem[];
}
const settings: MenuItem = {
label: "Settings",
children: [{ label: "Billing", children: [] }],
};
console.log(settings.children[0].label);→ Billing
The course still defaults to type because recursion does not require interface. The LaunchComment[] part is only the array syntax you already know: an array of the same shape.
Next up, you tighten object shapes with optional properties, readonly, and index signatures. The type-first rule stays in place; the sharper tools just make each promise more precise.
Checkpoint
Answer all three to mark this lesson complete