import 'reflect-metadata'; import { DI, Injectable, Inject, Scope } from '../src/common'; // ===== INTERFACES ===== interface IUserService { getUser(id: string): Promise; createUser(userData: CreateUserData): Promise; } interface IUserRepository { findById(id: string): Promise; save(user: User): Promise; } interface IEmailService { sendEmail(to: string, subject: string, body: string): Promise; } // ===== TYPES ===== interface User { id: string; name: string; email: string; createdAt: Date; } interface CreateUserData { name: string; email: string; } // ===== IMPLEMENTATIONS ===== @Injectable() class UserRepository implements IUserRepository { private users: User[] = []; async findById(id: string): Promise { return this.users.find(user => user.id === id) || null; } async save(user: User): Promise { this.users.push(user); return user; } } @Injectable() class EmailService implements IEmailService { async sendEmail(to: string, subject: string, body: string): Promise { console.log(`📧 Sending email to ${to}: ${subject}`); console.log(`Body: ${body}`); } } @Injectable() class UserService implements IUserService { constructor( @Inject('IUserRepository') private userRepo: IUserRepository, @Inject('IEmailService') private emailService: IEmailService ) {} async getUser(id: string): Promise { const user = await this.userRepo.findById(id); if (!user) { throw new Error(`User with id ${id} not found`); } return user; } async createUser(userData: CreateUserData): Promise { const user: User = { id: Math.random().toString(36).substr(2, 9), name: userData.name, email: userData.email, createdAt: new Date() }; const savedUser = await this.userRepo.save(user); // Send welcome email await this.emailService.sendEmail( user.email, 'Welcome!', `Hello ${user.name}, welcome to our platform!` ); return savedUser; } } // ===== CONFIGURATION ===== interface AppConfig { port: number; environment: string; database: { host: string; port: number; name: string; }; } const appConfig: AppConfig = { port: 3000, environment: 'development', database: { host: 'localhost', port: 5432, name: 'myapp' } }; // ===== FACTORY FUNCTIONS ===== function createDatabaseConnection(config: AppConfig) { console.log(`🔌 Connecting to database: ${config.database.host}:${config.database.port}/${config.database.name}`); return { connect: () => console.log('✅ Database connected'), disconnect: () => console.log('❌ Database disconnected') }; } // ===== REGISTRATION WITH INVERSIFY-STYLE API ===== async function setupDI() { console.log('🚀 Setting up Dependency Injection with Inversify-style API...\n'); // 1. String tokens + classes DI.bind('IUserRepository').toClass(UserRepository); DI.bind('IEmailService').toClass(EmailService); DI.bind('IUserService').toClass(UserService, { dependencies: ['IUserRepository', 'IEmailService'] }); // 3. Values/instances DI.bind('AppConfig').toValue(appConfig); // 4. Factory functions DI.bind('DatabaseConnection').toFactory( (config: AppConfig) => createDatabaseConnection(config), { scope: Scope.SINGLETON, dependencies: ['AppConfig'] } ); // 5. Symbol tokens const USER_SERVICE_TOKEN = Symbol('UserService'); DI.bind(USER_SERVICE_TOKEN).toClass(UserService); // 6. With options DI.bind('TransientService').toClass(UserService, { scope: Scope.TRANSIENT }); console.log('✅ All dependencies registered!\n'); } // ===== USAGE ===== async function demonstrateUsage() { console.log('📋 Demonstrating usage...\n'); // Get services const userService = DI.get('IUserService'); const config = DI.get('AppConfig'); const dbConnection = DI.get('DatabaseConnection'); console.log('📊 Application Configuration:'); console.log(`Port: ${config.port}`); console.log(`Environment: ${config.environment}`); console.log(`Database: ${config.database.host}:${config.database.port}/${config.database.name}\n`); // Connect to database dbConnection.connect(); // Create a user console.log('👤 Creating user...'); const newUser = await userService.createUser({ name: 'John Doe', email: 'john@example.com' }); console.log(`✅ User created: ${newUser.name} (${newUser.email})\n`); // Get the user console.log('🔍 Retrieving user...'); const retrievedUser = await userService.getUser(newUser.id); console.log(`✅ User retrieved: ${retrievedUser.name} (${retrievedUser.email})\n`); // Disconnect from database dbConnection.disconnect(); } // ===== MANAGEMENT ===== function showDIInfo() { console.log('📊 DI Container Information:'); console.log(`Registered tokens: ${DI.getTokens().length}`); console.log('Tokens:', DI.getTokens()); console.log(); // Show provider info const userServiceProvider = DI.getProvider('IUserService'); if (userServiceProvider) { console.log('UserService Provider:', { token: userServiceProvider.token, scope: userServiceProvider.scope, hasClass: !!userServiceProvider.useClass, hasValue: !!userServiceProvider.useValue, hasFactory: !!userServiceProvider.useFactory }); } } // ===== MAIN ===== async function main() { try { await setupDI(); await demonstrateUsage(); showDIInfo(); console.log('🎉 Inversify-style DI example completed successfully!'); } catch (error) { console.error('❌ Error:', error); } } // Run the example if (require.main === module) { main(); } export { main as runInversifyStyleExample };