Difficulty: Intermediate
The `implements` keyword in TypeScript allows a class to declare that it satisfies the contract defined by one or more interfaces. When a class implements an interface, TypeScript checks that the class provides all the properties and methods the interface requires. If anything is missing or has the wrong type, you get a compile-time error.
Implementing interfaces is a form of contract enforcement. An interface says "any class implementing me must have these members" without dictating how they should be implemented. This is different from abstract classes, which can provide partial implementations. Interfaces are purely structural - they define shape, not behavior.
A class can implement multiple interfaces by separating them with commas: `class Foo implements Bar, Baz`. This is TypeScript's answer to multiple inheritance. Since interfaces have no implementation, there is no ambiguity about which parent's code to use - the class must provide all implementations itself. This makes multiple interface implementation safe and straightforward.
It is important to understand that TypeScript uses structural typing. Even without the `implements` keyword, if an object has the right shape, it is compatible with the interface. The `implements` clause does not change the type of the class - it only serves as a compile-time check that the class satisfies the interface contract. This is a common source of confusion for developers coming from nominally-typed languages like Java or C#.
interface Printable {
toString(): string;
}
interface Loggable {
log(): void;
}
class Message implements Printable, Loggable {
constructor(private text: string) {}
toString(): string {
return `Message: ${this.text}`;
}
log(): void {
console.log(this.toString());
}
}
const msg = new Message("Hello, TypeScript!");
msg.log();
console.log(msg.toString());
The Message class implements both Printable and Loggable interfaces, providing concrete implementations for toString() and log().
interface Serializable {
serialize(): string;
}
interface Identifiable {
id: string;
getName(): string;
}
class Product implements Identifiable, Serializable {
constructor(public id: string, private name: string, private price: number) {}
getName(): string {
return this.name;
}
serialize(): string {
return JSON.stringify({ id: this.id, name: this.name, price: this.price });
}
}
const p = new Product("p-1", "Laptop", 999);
console.log(p.getName());
console.log(p.serialize());
Product implements two interfaces, providing the required `id` property, `getName` method, and `serialize` method.
interface Renderable {
render(): string;
}
class Button implements Renderable {
constructor(private label: string) {}
render(): string {
return `<button>${this.label}</button>`;
}
}
class TextInput implements Renderable {
constructor(private placeholder: string) {}
render(): string {
return `<input placeholder="${this.placeholder}" />`;
}
}
function renderAll(items: Renderable[]): void {
items.forEach(item => console.log(item.render()));
}
renderAll([new Button("Submit"), new TextInput("Enter name")]);
Both Button and TextInput implement Renderable, so they can be stored in the same array and rendered polymorphically.
implements, interface, contract, multiple interfaces, structural typing