Interfaces
Learn how to describe object shapes with interfaces, including optional and readonly properties, extending interfaces, and structural typing.
On this page 12 sections
Introduction
Most real-world data isn't a single primitive value — it's an object with several properties: a user with an id, name, and email; a product with a price and description. Interfaces are TypeScript's primary tool for describing the shape of those objects.
- How to define an interface and use it to type an object.
- How to mark properties as optional or readonly.
- How to extend one interface with another to share common fields.
- How to describe function types using an interface.
- What structural typing means and why it matters in TypeScript.
What is an Interface?
An interface is a named description of an object's shape — which properties it must have, and what type each property is. Any object that has all of the required properties, with matching types, satisfies the interface.
interface User { id: number; name: string; email: string;}
function printUser(user: User): void { console.log(`${user.name} (${user.email})`);}
printUser({ id: 1, name: "Amol", email: "amol@example.com" });Click Run to see what this code prints.
Optional and Readonly Properties
Adding a ? after a property name makes it optional — objects satisfying the interface may omit it entirely. Adding readonly before a property means it can be set once (usually at creation) but never reassigned afterward.
interface Product { readonly id: number; name: string; discount?: number; // optional}
const item: Product = { id: 101, name: "Keyboard" };// item.id = 202; // Error: 'id' is readonlyExtending Interfaces
One interface can build on another with extends, inheriting all of its properties. This avoids repeating shared fields across related shapes.
interface Employee extends User { department: string;}
const worker: Employee = { id: 2, name: "Priya", email: "priya@example.com", department: "Engineering",};Interfaces for Functions
Interfaces can also describe the shape of a function — its parameters and return type — which is useful when you want to name a reusable "callback shape."
interface Comparator { (a: number, b: number): number;}
const ascending: Comparator = (a, b) => a - b;Structural Typing
TypeScript uses structural typing, sometimes called "duck typing": what matters is whether an object's *shape* matches an interface, not whether it was explicitly declared to implement it. This mirrors how JavaScript already works at runtime — objects don't carry a formal "type name" with them, only their actual properties.
Implementing Interfaces in Classes
A class can declare that it satisfies an interface using implements, which the compiler checks and enforces. You'll see this in depth in the classes lesson, but the shape is: class Manager implements Employee { ... } — TypeScript then requires every property and method the interface declares.
Common Mistakes
- Being surprised by "excess property check" errors when passing an object literal with extra fields directly into a function expecting an interface.
- Assuming
readonlymakes nested objects fully immutable — it is shallow; a readonly property holding an object can still have its own inner properties changed. - Forgetting that declaring the same interface name twice is actually valid TypeScript — interfaces merge declarations, unlike type aliases.
- Prefixing interface names with "I" (e.g.
IUser) out of habit from other languages — that convention is not idiomatic in TypeScript/JavaScript.
Best Practices
- Name interfaces after what they represent (
User,ApiResponse), without an "I" prefix. - Mark properties
readonlywhenever they are set once and never intended to change. - Prefer extending a shared base interface over duplicating common fields across related shapes.
- Use interfaces to describe the public shape of objects and classes, especially in code that other modules will consume.
Frequently Asked Questions
TypeScript compares shapes, not names — any object with the right properties satisfies an interface, even if it was never explicitly declared to implement it.
Yes — interface C extends A, B {} is valid and combines the properties of both.
age?: number allows the key to be entirely absent from the object. age: number | undefined requires the key to exist, but permits its value to be undefined.
No — like all TypeScript types, interfaces are fully erased during compilation and have no representation in the compiled JavaScript.
Key Takeaways
- Interfaces describe the shape of an object: its properties and their types.
?marks a property optional;readonlyprevents reassignment after creation.- Interfaces can extend other interfaces to share common fields.
- TypeScript uses structural typing — matching shape is what satisfies an interface, not an explicit declaration.
- Classes can use
implementsto guarantee they satisfy a given interface.
Summary
You can now describe the shape of objects with interfaces, including optional and readonly properties and extension. Next, you'll learn type aliases and union types — TypeScript's tools for describing values that can be one of several types, and how they compare to interfaces.