Challenge 2: Build a Minimal Container — Possible Solution ==================================================================== class Token { constructor(public readonly name: string) {} } type Factory = () => T; class Container { private factories = new Map, Factory>(); register(token: Token, factory: Factory): void { this.factories.set(token, factory); } resolve(token: Token): T { const factory = this.factories.get(token) as Factory | undefined; if (!factory) { throw new Error(`No registration for ${token.name}`); } return factory(); } } // --- Usage: two services sharing a dependency --- interface Clock { now(): Date; } class SystemClock implements Clock { now(): Date { return new Date(); } } class AuditLogger { constructor(private clock: Clock) {} log(event: string): void { console.log(`[${this.clock.now().toISOString()}] ${event}`); } } class OrderProcessor { constructor( private clock: Clock, private auditLogger: AuditLogger ) {} process(orderId: string): void { this.auditLogger.log(`Processing order ${orderId} at ${this.clock.now()}`); } } const ClockToken = new Token("Clock"); const AuditLoggerToken = new Token("AuditLogger"); const OrderProcessorToken = new Token("OrderProcessor"); const container = new Container(); container.register(ClockToken, () => new SystemClock()); container.register(AuditLoggerToken, () => new AuditLogger(container.resolve(ClockToken))); container.register(OrderProcessorToken, () => new OrderProcessor(container.resolve(ClockToken), container.resolve(AuditLoggerToken)) ); const processor = container.resolve(OrderProcessorToken); // typed as OrderProcessor processor.process("ORD-123"); WHY THIS WORKS -------------- - Token exists purely to carry a compile-time type parameter — at runtime it's just an object used as a Map key, but resolve() returns T, not unknown. - Both AuditLogger and OrderProcessor resolve Clock independently, but since factories are just functions, you could make ClockToken a singleton (see Challenge 3) so they share one instance. - No casting to `any` is needed anywhere at the call site — resolve() always returns the type that was registered for that token.