Interfaces
Learn how to describe the shape of objects using interfaces, and how interfaces can extend one another.
Reading Time
16 min
Lesson
Lesson 9 of 30
What is an Interface?
An interface describes the shape an object must have — which properties it needs, and what type each one is. Any object matching that shape satisfies the interface, regardless of how it was created.
A Basic Interface
interface User {
id: number;
name: string;
email: string;
}
function printUser(user: User) {
console.log(`${user.name} <${user.email}>`);
}
printUser({ id: 1, name: "Alice", email: "alice@example.com" });Structural Typing
TypeScript uses structural typing — an object satisfies an interface if it has the required shape, even if it was never explicitly declared as that interface. This is sometimes called "duck typing."
Structural Typing in Action
interface Point {
x: number;
y: number;
}
function printPoint(p: Point) {
console.log(`(${p.x}, ${p.y})`);
}
const location = { x: 10, y: 20, label: "Home" };
printPoint(location); // Works — has at least x and yExtending Interfaces
An interface can extend one or more other interfaces with the extends keyword, inheriting all of their members.
Extending an Interface
interface Animal {
name: string;
}
interface Dog extends Animal {
breed: string;
}
const myDog: Dog = { name: "Rex", breed: "Labrador" };Optional and Readonly Properties
A property marked with ? is optional, and one marked readonly cannot be reassigned after the object is created.
Optional and Readonly
interface Config {
readonly apiUrl: string;
timeout?: number;
}
const config: Config = { apiUrl: "https://api.example.com" };
config.apiUrl = "https://other.com"; // Error: read-only propertyInterfaces for Functions and Classes
Interfaces can also describe callable function shapes, and classes can formally implement an interface with the implements keyword to guarantee they provide a matching shape.
A Class Implementing an Interface
interface Shape {
area(): number;
}
class Circle implements Shape {
constructor(private radius: number) {}
area(): number {
return Math.PI * this.radius ** 2;
}
}Best Practice
Use interfaces to describe the public shape of objects and class contracts. They’re easily extendable and produce clearer error messages than deeply nested type aliases.