Interfaces and Type Aliases
Give a shape a name so it can be reused, extended, and referred to in one place.
What you'll learn
- Name an object shape with an interface or a type alias
- Extend one shape from another
- Choose between `interface` and `type` with a defensible reason
Prerequisites
Explanation
Repeating { title: string; minutes: number } in five places means five places to edit when a field changes, and five chances to get it wrong. Name the shape once instead.
Two ways to name a shape
interface Lesson {
title: string;
minutes: number;
}
type LessonAlias = {
title: string;
minutes: number;
};
For describing an object, these are interchangeable. Both are erased at runtime, both check identically, and you can use either wherever a type is expected.
Where they differ
interface can be extended, and reopened.
interface Content {
title: string;
}
interface Lesson extends Content {
minutes: number;
}
Lesson now requires both fields. Interfaces also support declaration merging: declaring the same interface name twice merges the members rather than erroring. That is occasionally essential when augmenting types from a library, and occasionally a confusing accident in your own code.
type can name things that are not objects. A union, a primitive, a function signature:
type Status = "draft" | "published";
type Minutes = number;
type Formatter = (value: string) => string;
Interfaces cannot express those. type composes with & instead of extends:
type Lesson = Content & { minutes: number };
Choosing
A defensible default: interface for object shapes, type for everything else. Interfaces produce slightly clearer error messages for objects and communicate "this is a thing with fields," while type is the only option for unions and function types — which you will meet in lessons 5 and 7.
What matters more than the choice is consistency within a codebase. Mixing both for object shapes with no rule behind it makes readers wonder what distinction you intended.
Naming shapes is design work
An interface is documentation the compiler enforces. interface User { id: string; email: string } states that every user has both, everywhere, forever. When that stops being true the compiler tells you every place that assumed otherwise — which is precisely the leverage you are buying.
Example
A base shape, an extended shape, and a type alias for something an interface could not express.
interface Content {
title: string;
author: string;
}
interface Lesson extends Content {
minutes: number;
}
type Status = "draft" | "published";
const lesson: Lesson = {
title: "Interfaces and Type Aliases",
author: "Curriculum Team",
minutes: 22,
};
const status: Status = "published";
console.log(lesson.title + " by " + lesson.author + " (" + status + ")");Try it yourself
Add a `level` field to Lesson. Then try setting status to "archived" and read the error.
Code editor. Press Escape then Tab to leave the editor if keyboard focus becomes trapped. Press Control+Shift+M inside the editor to toggle Tab-key focus trapping.
Guided exercise
Guided exercise
Define an interface `Book` with `title` (string) and `pages` (number). Create a `Book` called `currentBook`, then write `isLong(): boolean` returning true when the book has more than 300 pages.
Checks: currentBook has a string title · currentBook has a number pages · isLong() matches pages > 300
Code editor. Press Escape then Tab to leave the editor if keyboard focus becomes trapped. Press Control+Shift+M inside the editor to toggle Tab-key focus trapping.
Stuck? Get a hint.
Independent exercise
Independent exercise
Define `interface Person { name: string }` and `interface Employee extends Person { role: string }`. Create an `Employee` named `staffMember`, then write `describe(): string` returning `"Ada — Engineer"` style text (name, space, em dash, space, role).
Checks: staffMember has name and role · describe is defined · describe() joins name and role with an em dash
Code editor. Press Escape then Tab to leave the editor if keyboard focus becomes trapped. Press Control+Shift+M inside the editor to toggle Tab-key focus trapping.
Stuck? Get a hint.
Common mistakes
- Trying to express a union with an interface. `interface Status = "a" | "b"` is not valid — unions need `type`.
- Assuming an interface exists at runtime. Like every other type, it is erased; you cannot check `instanceof` against it.
- Mixing `interface` and `type` for object shapes at random, leaving readers to guess whether the difference was meaningful.
Knowledge check
Takeaway
Name a shape once with `interface`, reach for `type` when the thing you are naming is not an object.
Summary
Interfaces and type aliases both name shapes. Interfaces extend and merge and read well for objects; type aliases are required for unions, primitives, and function signatures. Both vanish at runtime.
References
Your notes
Notes save automatically.
Finished this lesson?
Mark it complete to track your progress and schedule a future review.
AI tutor
The optional AI tutor isn't enabled in this deployment. All lessons, exercises, quizzes, and search work fully without it.