@verbose/di
npm install @verbose/diDependency injection container with TypeScript decorators, token-based resolution, and scoped containers.
Basic Usage
import { Injectable, Inject, container } from '@verbose/di'
@Injectable()
class LoggerService {
log(msg: string) {
console.log('[LOG]', msg)
}
}
@Injectable()
class UserService {
@Inject(LoggerService) private logger!: LoggerService
greet(name: string) {
this.logger.log(`Hello, ${name}`)
}
}
const userService = container.resolve(UserService)
userService.greet('Alice')@Injectable(options?)
Registers a class in the global container.
@Injectable({ scope: 'singleton' })
class CacheService { /* ... */ }
@Injectable({ scope: 'transient' })
class RequestContext { /* ... */ }Options:
| Option | Type | Default | Description |
|---|---|---|---|
scope | 'singleton' | 'transient' | 'singleton' | Singleton shares one instance; transient creates a new one on each resolve |
@Inject<T>(dep)
Lazily injects a dependency into a class property. Resolves and caches on first access. In development, blocks direct property assignment to prevent bypassing the container.
@Injectable()
class ApiClient {
@Inject(AuthService) private auth!: AuthService
@Inject(HTTP_CLIENT) private http!: HttpClient // token injection
async get(path: string) {
return this.http.get(path, { token: this.auth.token })
}
}dep can be a class constructor or a Token<T>.
@InjectContainer()
Injects the DI container itself. Useful for dynamic resolution.
@Injectable()
class ServiceLocator {
@InjectContainer() private container!: Container
resolve<T>(type: Constructor<T>): T {
return this.container.resolve(type)
}
}Tokens
Use tokens for injecting values that aren't classes (primitives, config objects, interfaces).
token<T>(description)
Creates a typed injection token.
import { token } from '@verbose/di'
const API_URL = token<string>('API_URL')
const HTTP_OPTIONS = token<HttpOptions>('HTTP_OPTIONS')Registering token values
container.registerValue(API_URL, 'https://api.example.com')
container.registerValue(HTTP_OPTIONS, { timeout: 5000 })Injecting tokens
@Injectable()
class ApiService {
@Inject(API_URL) private baseUrl!: string
}Container
The global container instance is available as a named export. You can also create child containers for isolated scopes.
container.register(target, options?)
Manually register a class.
container.register(MyService, { scope: 'transient' })container.registerValue(token, value)
Register a plain value.
container.registerValue(API_URL, 'https://api.example.com')container.registerFactory(token, factory)
Register a factory function that receives the container and returns the value.
container.registerFactory(LOGGER, (c) => {
const config = c.resolve(AppConfig)
return config.debug ? new DebugLogger() : new SilentLogger()
})container.resolve(target)
Resolves a class or token from the container.
const service = container.resolve(UserService)
const url = container.resolve(API_URL)container.createChild()
Creates a child container that inherits all registrations from its parent but has its own scope for new registrations.
const requestScope = container.createChild()
requestScope.registerValue(REQUEST_ID, generateId())createScope()
Shorthand for creating a scoped child container. Useful for request-level or component-level isolation.
import { createScope } from '@verbose/di'
const scope = createScope()
scope.registerValue(SESSION, session)
const handler = scope.resolve(RequestHandler)useService<T>(ServiceClass)
Composable to resolve a service from the global container inside a component.
import { useService } from '@verbose/di'
@Component()
class Dashboard extends BaseComponent {
analytics = useService(AnalyticsService)
render() {
return <div onMount={() => this.analytics.track('view')} />
}
}