typescript / intermediate
Snippet
Building a Lightweight Dependency Injection Container
Dependency injection (DI) is a core architectural pattern used in modern application frameworks. Using TypeScript's generics and Symbols, you can build a light, type-safe DI container that maps unique typed tokens to service implementations without relying on reflection or external decorators.
snippet.ts
typescript
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
type Token<T> = { readonly id: symbol };function createToken<T>(description: string): Token<T> {return { id: Symbol(description) };}class ServiceContainer {private services = new Map<symbol, unknown>();register<T>(token: Token<T>, instance: T): void {this.services.set(token.id, instance);}resolve<T>(token: Token<T>): T {const service = this.services.get(token.id);if (!service) {throw new Error(`Service not registered for token: ${token.id.toString()}`);}return service as T;}}interface Logger {log(msg: string): void;}const LoggerToken = createToken<Logger>("Logger");const container = new ServiceContainer();container.register(LoggerToken, { log: (msg) => console.log(msg) });const logger = container.resolve(LoggerToken);logger.log("DI Container initialized");
Breakdown
1
type Token<T> = { readonly id: symbol };
Defines a strongly-typed token carrying generic phantom type metadata for type preservation.
2
class ServiceContainer {
Encapsulates dependency registration and resolution mechanisms.
3
register<T>(token: Token<T>, instance: T): void
Binds a specific service implementation to its typed token inside an internal Map.
4
resolve<T>(token: Token<T>): T
Retrieves and type-casts the registered dependency using the token's unique symbol key.