implements keyword allows a class to declare that it fulfills that contract. This enables Polymorphism and the Dependency Inversion Principle, ensuring disparate classes expose identical, predictable APIs.1. The implements Contract Validation#
When a class declares implements InterfaceName, TypeScript acts as a strict compliance inspector. It verifies that the class implements every public field and method specified by the interface.
interface PaymentGateway {
name: string;
processPayment(amount: number, currency: string): Promise<boolean>;
refund(transactionId: string): Promise<boolean>;
}
// 🟢 StripeGateway promises to implement PaymentGateway
class StripeGateway implements PaymentGateway {
public name = "Stripe";
public async processPayment(amount: number, currency: string): Promise<boolean> {
console.log(`Processing Stripe payment of ${amount} ${currency}`);
return true;
}
public async refund(transactionId: string): Promise<boolean> {
console.log(`Refunding Stripe transaction: ${transactionId}`);
return true;
}
}What Happens When a Contract is Broken?#
If a class fails to implement even one required method, or provides incorrect parameter types, TypeScript rejects compilation:
// ❌ Compiler Error: Class 'PayPalGateway' incorrectly implements interface 'PaymentGateway'.
// Property 'refund' is missing in type 'PayPalGateway' but required in type 'PaymentGateway'.
class PayPalGateway implements PaymentGateway {
public name = "PayPal";
public async processPayment(amount: number, currency: string): Promise<boolean> {
return true;
}
// Forgot refund() method!
}2. A Crucial Misconception: implements Does NOT Infer Method Parameter Types!#
A very common surprise for TypeScript developers is discovering that writing implements Interface does NOT automatically infer parameter types for the class methods!
interface Logger {
log(message: string): void;
}
class ConsoleLogger implements Logger {
// ❌ Compiler Error: Parameter 'message' implicitly has an 'any' type.
// TypeScript DOES NOT automatically copy parameter types from the interface to the class method body!
/*
log(message) {
console.log(message);
}
*/
// 🟢 CORRECT: You MUST still explicitly annotate method parameters inside the class!
log(message: string): void {
console.log(`[LOG]: ${message}`);
}
}The Inspection Rule: The implements clause is purely a validation check, NOT a type transformer. It checks your class after it is typed; it does not inject types into method signatures.
3. Implementing Multiple Interfaces#
Unlike classical inheritance (where a class can only extend one parent class), a TypeScript class can implement an arbitrary number of interfaces separated by commas:
interface Serializable {
serialize(): string;
}
interface Authenticatable {
verifyToken(token: string): boolean;
}
interface Auditable {
readonly createdAt: Date;
}
// Fulfills ALL 3 Contracts simultaneously
class SecureUserSession implements Serializable, Authenticatable, Auditable {
public readonly createdAt = new Date();
constructor(public readonly userId: string) {}
public serialize(): string {
return JSON.stringify({ userId: this.userId, createdAt: this.createdAt });
}
public verifyToken(token: string): boolean {
return token.startsWith(`usr_${this.userId}_`);
}
}4. Public Contracts Only Rule#
Interfaces can only declare the public shape of an object. You cannot declare private or protected members in an interface.
interface DatabaseConnection {
// ❌ Compiler Error: 'private' modifier cannot appear on a type member.
// private connectionString: string;
connect(): void;
disconnect(): void;
}An interface represents how the outside world interacts with instances of your class. The internal private backing implementation is an internal concern of the class itself:
class PostgresConnection implements DatabaseConnection {
// Private property added independently by the class to support internal logic
private connectionString: string;
constructor(uri: string) {
this.connectionString = uri;
}
public connect(): void {
console.log(`Connecting to ${this.connectionString}`);
}
public disconnect(): void {
console.log("Disconnected.");
}
}5. Polymorphism & The Dependency Inversion Principle#
Why do we bother writing interfaces and implements clauses?
It enables the Dependency Inversion Principle (DIP) (the “D” in SOLID design principles). High-level business logic should depend on abstractions (Interfaces), not concrete implementations (Classes).
// High-Level Business Processor depends on the PaymentGateway Interface, NOT Stripe or PayPal!
class CheckoutService {
constructor(private gateway: PaymentGateway) {}
public async completeOrder(orderId: string, total: number) {
console.log(`[Checkout]: Processing Order #${orderId}`);
const isSuccess = await this.gateway.processPayment(total, "USD");
if (!isSuccess) throw new Error("Payment failed.");
}
}
// We can seamlessly inject ANY class that implements PaymentGateway:
const stripeCheckout = new CheckoutService(new StripeGateway());Summary & Next Steps#
In this episode:
- We learned how
implementsvalidates class structural compliance at compile time. - We uncovered the Inspection Rule:
implementschecks your class, but does NOT automatically infer parameter types on method bodies. - We implemented multiple interfaces on a single class (
implements A, B, C). - We reinforced the Public Contract Rule (interfaces only declare public APIs).
- We demonstrated Polymorphism and the Dependency Inversion Principle.
In Episode 21: Inheritance and the super Keyword, we will explore class inheritance (extends), method overriding, and constructor chaining with super()!

