Name Collision Example
This example demonstrates how IoC Arise automatically handles classes with identical names across different directories using directory-based prefixing. You’ll learn how the container resolves naming conflicts while maintaining clean separation of concerns across different domains.
Project Structure
Section titled “Project Structure”Directoryname-collision-example/
Directoryuser/
- CreateItemUseCase.ts
- DeleteItemUseCase.ts
- GetItemUseCase.ts
- ListItemsUseCase.ts
- UpdateItemUseCase.ts
- UserController.ts
- UserRepository.ts
Directoryproduct/
- CreateItemUseCase.ts
- DeleteItemUseCase.ts
- GetItemUseCase.ts
- ListItemsUseCase.ts
- UpdateItemUseCase.ts
- ProductController.ts
- ProductRepository.ts
Directoryorder/
- CreateItemUseCase.ts
- DeleteItemUseCase.ts
- GetItemUseCase.ts
- ListItemsUseCase.ts
- UpdateItemUseCase.ts
- OrderController.ts
- OrderRepository.ts
- container.gen.ts
- ioc.config.json
- README.md
The Problem
Section titled “The Problem”Multiple classes have identical names across different domains:
- Three
CreateItemUseCase
classes (user, product, order) - Three
DeleteItemUseCase
classes (user, product, order) - Three
GetItemUseCase
classes (user, product, order) - Three
ListItemsUseCase
classes (user, product, order) - Three
UpdateItemUseCase
classes (user, product, order)
IoC Arise’s Solution
Section titled “IoC Arise’s Solution”IoC Arise automatically resolves name collisions using directory-based prefixing:
Name Resolution Strategy
Section titled “Name Resolution Strategy”-
Directory Prefix: Classes get prefixed with their directory name
user/CreateItemUseCase.ts
→UserCreateItemUseCase
product/CreateItemUseCase.ts
→ProductCreateItemUseCase
order/CreateItemUseCase.ts
→OrderCreateItemUseCase
-
Unique Import Aliases: Generated imports use unique aliases
import { CreateItemUseCase as UserCreateItemUseCase } from './user/CreateItemUseCase';import { CreateItemUseCase as ProductCreateItemUseCase } from './product/CreateItemUseCase';import { CreateItemUseCase as OrderCreateItemUseCase } from './order/CreateItemUseCase'; -
Predictable Naming: Easy to understand based on directory structure
Domain Implementations
Section titled “Domain Implementations”User Domain
Section titled “User Domain”export class CreateItemUseCase { constructor(private userRepository: IUserRepository) {}
async execute(itemData: { name: string; description: string }): Promise<void> { console.log(`Creating user item: ${itemData.name}`); await this.userRepository.saveUserItem(itemData); }}
Product Domain
Section titled “Product Domain”export class CreateItemUseCase { constructor(private productRepository: IProductRepository) {}
async execute(itemData: { name: string; price: number; category: string }): Promise<void> { console.log(`Creating product item: ${itemData.name} - $${itemData.price}`); await this.productRepository.saveProduct(itemData); }}
Order Domain
Section titled “Order Domain”export class CreateItemUseCase { constructor(private orderRepository: IOrderRepository) {}
async execute(itemData: { name: string; quantity: number; unitPrice: number }): Promise<void> { console.log(`Creating order item: ${itemData.name}`); await this.orderRepository.saveOrderItem(itemData); }}
Usage with Container
Section titled “Usage with Container”Method 1: Direct Container Access
Section titled “Method 1: Direct Container Access”import { container } from './container.gen';
// Access services with automatically prefixed namesconst userCreateUseCase = container.coreModule.UserCreateItemUseCase;const productCreateUseCase = container.coreModule.ProductCreateItemUseCase;const orderCreateUseCase = container.coreModule.OrderCreateItemUseCase;
// All repositories and controllers are similarly prefixedconst userRepo = container.coreModule.UserRepository;const productRepo = container.coreModule.ProductRepository;const orderRepo = container.coreModule.OrderRepository;
const userController = container.coreModule.UserController;const productController = container.coreModule.ProductController;const orderController = container.coreModule.OrderController;
Method 2: Using inject() Function (Type-Safe)
Section titled “Method 2: Using inject() Function (Type-Safe)”import { inject } from './container.gen';
// Access services using directory-prefixed names with full type safetyconst userCreateUseCase = inject('coreModule.UserCreateItemUseCase');const productCreateUseCase = inject('coreModule.ProductCreateItemUseCase');const orderCreateUseCase = inject('coreModule.OrderCreateItemUseCase');
// Access other similarly named servicesconst userListUseCase = inject('coreModule.UserListItemsUseCase');const productListUseCase = inject('coreModule.ProductListItemsUseCase');const orderListUseCase = inject('coreModule.OrderListItemsUseCase');
Example Usage
Section titled “Example Usage”// Each service works with its own domain data structureawait userCreateUseCase.execute({ name: 'User Profile', description: 'User profile information'});
await productCreateUseCase.execute({ name: 'Laptop', price: 999.99, category: 'Electronics'});
await orderCreateUseCase.execute({ name: 'Order Item', quantity: 2, unitPrice: 49.99});
// List items from each domainconst userItems = await userListUseCase.execute();const productItems = await productListUseCase.execute();const orderItems = await orderListUseCase.execute();
console.log('User items:', userItems);console.log('Product items:', productItems);console.log('Order items:', orderItems);
Cross-Domain Dependencies (Advanced)
Section titled “Cross-Domain Dependencies (Advanced)”You can use post-construction injection for cross-domain dependencies:
// Example: Order service that validates productsexport class OrderCreateItemUseCase { private productRepository: IProductRepository;
constructor(private orderRepository: IOrderRepository) {}
// Would be called if this was in the container's onInit function initializeCrossDomainDependencies(): void { this.productRepository = inject('coreModule.ProductRepository'); }
async execute(itemData: { name: string; quantity: number; unitPrice: number }): Promise<void> { // Validate product exists before creating order const product = await this.productRepository.getProduct(itemData.name); if (!product) { throw new Error(`Product ${itemData.name} not found`); }
await this.orderRepository.saveOrderItem(itemData); }}
Post-Construction Initialization
Section titled “Post-Construction Initialization”The onInit()
function is exported from the generated container.gen.ts file, not a method in your classes:
import { onInit } from './container.gen';
// The onInit function is called automatically when inject() is first used// You can modify it in the generated container.gen.ts file for custom initialization
IoC Configuration
Section titled “IoC Configuration”{ "srcDir": ".", "outputFile": "container.gen.ts"}
This minimal configuration:
- Scans the current directory for classes
- Automatically detects name collisions
- Applies directory-based prefixing to resolve conflicts
- Generates a single coreModule container
Name Resolution Examples
Section titled “Name Resolution Examples”Original File Path | Generated Service Name |
---|---|
user/CreateItemUseCase.ts | UserCreateItemUseCase |
product/CreateItemUseCase.ts | ProductCreateItemUseCase |
order/CreateItemUseCase.ts | OrderCreateItemUseCase |
user/UserController.ts | UserController |
product/ProductController.ts | ProductController |
order/OrderController.ts | OrderController |
Benefits of Automatic Name Resolution
Section titled “Benefits of Automatic Name Resolution”- Automatic Resolution: IoC Arise automatically detects and resolves name collisions
- Predictable Naming: Directory-based prefixing is easy to understand and predict
- Type Safety: Full TypeScript support with proper type inference for all prefixed names
- Clean Separation: Each domain maintains its own classes with identical names
- No Manual Configuration: Works automatically without additional configuration
- Maintainable: Clear naming convention based on directory structure
- Scalable: Easy to add new domains without worrying about name conflicts
This example shows how IoC Arise intelligently handles naming conflicts, making it perfect for large applications with multiple domains that naturally have similar operations and naming patterns!