typescript / expert
Snippet
Type-Safe Dependency Injection Registry Pattern
This expert pattern uses opaque tokens with phantom data traits (`_type!: T`) to build a lightweight, fully type-safe dependency injection container without reliance on experimental decorators or metadata reflection libraries.
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
abstract class ServiceToken<T> {readonly _type!: T;}function createToken<T>(description: string): ServiceToken<T> {return { description } as unknown as ServiceToken<T>;}class Container {private services = new Map<ServiceToken<any>, any>();register<T>(token: ServiceToken<T>, instance: T): void {this.services.set(token, instance);}resolve<T>(token: ServiceToken<T>): T {const instance = this.services.get(token);if (!instance) throw new Error('Service not registered');return instance as T;}}interface Logger { log(msg: string): void; }const LOGGER_TOKEN = createToken<Logger>('LoggerService');const container = new Container();container.register(LOGGER_TOKEN, { log: console.log });const logger = container.resolve(LOGGER_TOKEN);
Breakdown
1
abstract class ServiceToken<T> { readonly _type!: T; }
Creates a typed token marker carrying a phantom generic field for compile-time type extraction.
2
private services = new Map<ServiceToken<any>, any>();
Stores services internally using tokens as dictionary keys while keeping runtime payload flexible.
3
register<T>(token: ServiceToken<T>, instance: T): void
Enforces that the registered service instance strictly satisfies the type specified by the token.
4
resolve<T>(token: ServiceToken<T>): T
Guarantees compile-time return type safety corresponding to the token passed.