---
title: Dependency Inversion
description: High-level modules should not depend on low-level modules; both should depend on abstractions.
tokens: ~427
---

# Dependency Inversion

Your code should depend on abstractions, not concrete implementations. Instead of a service creating its dependency directly, it should receive an interface through the constructor.

This matters for both testing and flexibility. When a service is coupled to a concrete class, you can't unit test without the real thing, and you can't swap the implementation without modifying the service. When it depends on an interface, you inject a mock for testing or a different implementation for a different context.

Note that DIP is a design principle, while dependency injection — passing dependencies through the constructor — is just one technique for achieving it.

## Example

`NotificationService` creates `EmailSender` directly, so it is tightly coupled to email:

```typescript
class EmailSender {
  send(message: string): void {
    // send email
  }
}

class NotificationService {
  private sender = new EmailSender();

  notify(message: string): void {
    this.sender.send(message);
  }
}
```

Define an interface based on what `NotificationService` needs, then inject the implementation:

```typescript
interface MessageSender {
  send(message: string): void;
}

class EmailSender implements MessageSender {
  send(message: string): void {
    // send email
  }
}

class SmsSender implements MessageSender {
  send(message: string): void {
    // send SMS
  }
}

class NotificationService {
  constructor(private sender: MessageSender) {}

  notify(message: string): void {
    this.sender.send(message);
  }
}
```

Now `NotificationService` knows nothing about email or SMS. You can swap the sender by passing a different implementation, and you can test with a mock that does not send real messages.