Created
November 3, 2024 00:04
-
-
Save greenido/43da003aff88da0f05d23c0d07bb1b5b to your computer and use it in GitHub Desktop.
Dependency Injection Examples in TypeScript
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 1. Interfaces for our dependencies | |
interface ILogger { | |
log(message: string): void; | |
} | |
interface IEmailService { | |
sendEmail(to: string, subject: string, content: string): Promise<boolean>; | |
} | |
interface IUserRepository { | |
findById(id: string): Promise<User>; | |
save(user: User): Promise<void>; | |
} | |
// 2. Implementation of our dependencies | |
class ConsoleLogger implements ILogger { | |
log(message: string): void { | |
console.log(`[${new Date().toISOString()}] ${message}`); | |
} | |
} | |
class SmtpEmailService implements IEmailService { | |
constructor(private smtpHost: string, private smtpPort: number) {} | |
async sendEmail(to: string, subject: string, content: string): Promise<boolean> { | |
// Implementation for SMTP email sending | |
console.log(`Sending email to ${to}`); | |
return true; | |
} | |
} | |
// 3. Domain Models | |
class User { | |
constructor( | |
public id: string, | |
public email: string, | |
public name: string | |
) {} | |
} | |
// 4. Constructor Injection Example | |
class UserService { | |
constructor( | |
private readonly userRepository: IUserRepository, | |
private readonly emailService: IEmailService, | |
private readonly logger: ILogger | |
) {} | |
async updateUserProfile(userId: string, newName: string): Promise<void> { | |
this.logger.log(`Updating profile for user ${userId}`); | |
const user = await this.userRepository.findById(userId); | |
if (!user) { | |
throw new Error('User not found'); | |
} | |
user.name = newName; | |
await this.userRepository.save(user); | |
await this.emailService.sendEmail( | |
user.email, | |
'Profile Updated', | |
`Hello ${user.name}, your profile has been updated.` | |
); | |
} | |
} | |
// 5. Property Injection Example | |
class NotificationService { | |
// Properties can be injected after instantiation | |
public logger!: ILogger; | |
public emailService!: IEmailService; | |
async sendNotification(user: User, message: string): Promise<void> { | |
this.logger.log(`Sending notification to ${user.email}`); | |
await this.emailService.sendEmail( | |
user.email, | |
'New Notification', | |
message | |
); | |
} | |
} | |
// 6. Method Injection Example | |
class ReportGenerator { | |
generateReport(data: any[], logger: ILogger): string { | |
logger.log('Generating report...'); | |
// Report generation logic | |
return JSON.stringify(data); | |
} | |
} | |
// 7. Simple DIContainer implementation | |
class DIContainer { | |
private services: Map<string, any> = new Map(); | |
register(key: string, implementation: any): void { | |
this.services.set(key, implementation); | |
} | |
resolve<T>(key: string): T { | |
const service = this.services.get(key); | |
if (!service) { | |
throw new Error(`Service ${key} not found in container`); | |
} | |
return service as T; | |
} | |
} | |
// 8. Usage Example | |
// Create a simple DI container | |
const container = new DIContainer(); | |
// Register services | |
container.register('logger', new ConsoleLogger()); | |
container.register('emailService', new SmtpEmailService('smtp.example.com', 587)); | |
container.register('userRepository', new class implements IUserRepository { | |
async findById(id: string): Promise<User> { | |
return new User(id, '[email protected]', 'Test User'); | |
} | |
async save(user: User): Promise<void> { | |
console.log('Saving user:', user); | |
} | |
}); | |
// Create service with injected dependencies | |
const userService = new UserService( | |
container.resolve('userRepository'), | |
container.resolve('emailService'), | |
container.resolve('logger') | |
); | |
// 9. Testing Example | |
class MockEmailService implements IEmailService { | |
public emailsSent: Array<{to: string, subject: string, content: string}> = []; | |
async sendEmail(to: string, subject: string, content: string): Promise<boolean> { | |
this.emailsSent.push({to, subject, content}); | |
return true; | |
} | |
} | |
class MockLogger implements ILogger { | |
public logs: string[] = []; | |
log(message: string): void { | |
this.logs.push(message); | |
} | |
} | |
// Test example | |
async function testUserService() { | |
// Arrange | |
const mockLogger = new MockLogger(); | |
const mockEmailService = new MockEmailService(); | |
const userRepository = container.resolve<IUserRepository>('userRepository'); | |
const testUserService = new UserService( | |
userRepository, | |
mockEmailService, | |
mockLogger | |
); | |
// Act | |
await testUserService.updateUserProfile('123', 'New Name'); | |
// Assert | |
console.assert(mockLogger.logs.length > 0, 'Logger should have been called'); | |
console.assert(mockEmailService.emailsSent.length === 1, 'Email should have been sent'); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment