All topics
Servicesbeginner

Dependency Injection Fundamentals

Explain what dependency injection solves and how Angular's injector resolves a class's constructor dependencies.

Dependency Injection (DI) is arguably the single most important architectural idea to understand deeply before an Angular interview, because nearly every other advanced topic — testing, hierarchical providers, interceptors, the inject() function — builds directly on top of it. At its core, DI means a class declares what it needs (via constructor parameters or inject()) rather than constructing those dependencies itself with new SomeService(), and a separate system (the injector) is responsible for supplying them.

It's like ordering room service instead of stocking a hotel mini-fridge yourself — you specify what you need at the front desk, and the hotel's systems figure out how to get it to your room, so you never have to know (or care) which supplier or kitchen it came from.

Key Concepts

1
The motivating problem is coupling: if OrderService directly instantiates its own HttpClient and LoggerService inside its constructor, you can never substitute a mock HttpClient in a unit test, and you can never swap in a different logging implementation without editing OrderService's source. By asking for those dependencies as constructor parameters typed by interface or class, OrderService becomes agnostic to how they're created — testing frameworks and the app's real runtime configuration can each supply whatever concrete implementation makes sense for that context.
OrderServiceHttpClientLoggerService
2
Angular's injector resolves dependencies by looking at a class's constructor parameter types (using TypeScript's emitDecoratorMetadata and the @Injectable() decorator, which is what makes a class eligible for injection and lets Angular know its own dependencies too) and looking up a matching provider registered at some level of the injector hierarchy. If found, the injector either returns a cached singleton instance or constructs a new one according to the provider's configuration.
emitDecoratorMetadata@Injectable()
3
Interviewers frequently ask you to contrast DI with the Service Locator pattern (where a class actively asks a central registry for what it needs, rather than receiving it automatically) — DI is preferred because dependencies are visible and explicit right there in the constructor signature, making the class's requirements obvious just by reading its type, rather than hidden inside method bodies.