Instance Factories
An instance factory is an exported function whose explicit return type annotation resolves to a registered interface. No @factory annotation is needed — the return type is the detection signal. The function is registered under the interface name as the token, exactly like a class that implements the interface.
Step 1: Write Your Code
Section titled “Step 1: Write Your Code”Separate Parameters Pattern:
import { IAppConfig } from '../config/IAppConfig';import { ILogger } from '../logger/ILogger';import { IUserRepository } from './IUserRepository';
// The `: IUserRepository` return type is enough — no @factory needed.export function createUserRepository( config: IAppConfig, logger: ILogger,): IUserRepository { if (config.getStorageType() === 'persistent') { logger.info('Using persistent storage'); return new PersistentUserRepository(config.getDbPath()); } logger.info('Using in-memory storage'); return new InMemoryUserRepository();}Context Object Pattern:
import { IAppConfig } from '../config/IAppConfig';import { ILogger } from '../logger/ILogger';import { IUserRepository } from './IUserRepository';
export function createUserRepository( context: { config: IAppConfig; logger: ILogger },): IUserRepository { const { config, logger } = context; if (config.getStorageType() === 'persistent') { logger.info('Using persistent storage'); return new PersistentUserRepository(config.getDbPath()); } logger.info('Using in-memory storage'); return new InMemoryUserRepository();}Promise<IInterface> and Awaited<Promise<IInterface>> return types are also detected.
Step 2: Generate Container
Section titled “Step 2: Generate Container”npx @notjustcoders/ioc-arise generateStep 3: Generated Code
Section titled “Step 3: Generated Code”container.gen.d.ts:
import type { IUserRepository } from './repositories/IUserRepository';import type { IAppConfig } from './config/IAppConfig';import type { ILogger } from './logger/ILogger';
export interface ContainerRegistry { 'IUserRepository': IUserRepository; 'IAppConfig': IAppConfig; 'ILogger': ILogger;}container.gen.ts (separate params):
import { Container, Lifecycle } from '@notjustcoders/di-container';import type { ContainerRegistry } from './container.gen.d';import { createUserRepository } from './repositories/createUserRepository';import { appConfig } from './config/appConfig';import { consoleLogger } from './logger/consoleLogger';
export const container = new Container<ContainerRegistry>();
container.register('IUserRepository', { useFactory: createUserRepository, dependencies: ['IAppConfig', 'ILogger'], lifecycle: Lifecycle.Singleton,});
container.register('IAppConfig', { useValue: appConfig, lifecycle: Lifecycle.Singleton });container.register('ILogger', { useValue: consoleLogger, lifecycle: Lifecycle.Singleton });container.gen.ts (context object):
container.register('IUserRepository', { useFactory: (config, logger) => createUserRepository({ config, logger }), dependencies: ['IAppConfig', 'ILogger'], lifecycle: Lifecycle.Singleton,});Step 4: Use It
Section titled “Step 4: Use It”import { container } from './container.gen';
const repo = container.resolve('IUserRepository');// ^? IUserRepository — full type safetyUniqueness Rule
Section titled “Uniqueness Rule”❌ Multiple implementation providers found for interface 'IUserRepository': • class:InMemoryUserRepository • factory:createUserRepository