Web Development TypeScript Subjective
Oct 04, 2025

How do you implement a type-safe dependency injection container?

Detailed Explanation
Use generic constraints for service registration, conditional types for dependency resolution, and mapped types for service discovery. Basic DI Container: type ServiceMap = {}; type Constructor = new (...args: any[]) => T; class DIContainer { private services = new Map(); private singletons = new Map(); register(token: string, implementation: Constructor): void { this.services.set(token, implementation); } registerSingleton(token: string, implementation: Constructor): void { this.services.set(token, implementation); this.singletons.set(token, null); } resolve(token: string): T { if (this.singletons.has(token)) { let instance = this.singletons.get(token); if (!instance) { const Implementation = this.services.get(token); instance = new Implementation(); this.singletons.set(token, instance); } return instance; } const Implementation = this.services.get(token); return new Implementation(); } } Type-Safe Version: interface ServiceRegistry { UserService: UserService; EmailService: EmailService; DatabaseService: DatabaseService; } type ServiceToken = keyof ServiceRegistry; class TypeSafeDIContainer { private services = new Map(); register( token: K, implementation: Constructor ): void { this.services.set(token, implementation); } resolve(token: K): ServiceRegistry[K] { const Implementation = this.services.get(token); return new Implementation() as ServiceRegistry[K]; } } // Usage const container = new TypeSafeDIContainer(); container.register('UserService', UserServiceImpl); const userService = container.resolve('UserService'); // Type: UserService Decorator-Based DI: const INJECTION_TOKENS = new Map(); function Injectable(token: string) { return function (target: T) { return target; }; } function Inject(token: string) { return function (target: any, propertyKey: string | symbol | undefined, parameterIndex: number) { const existingTokens = INJECTION_TOKENS.get(target) || []; existingTokens[parameterIndex] = token; INJECTION_TOKENS.set(target, existingTokens); }; } @Injectable('UserService') class UserService { constructor(@Inject('DatabaseService') private db: DatabaseService) {} } Benefits: • Compile-time type safety for service resolution • Prevents injection of wrong service types • Excellent IDE autocomplete • Supports decorator-based injection.
Discussion (0)

No comments yet. Be the first to share your thoughts!

Share Your Thoughts
Feedback