API Reference
Based directly on TinyDI's implementation — every signature below is real, not illustrative.
createToken
function createToken<T>(description: string): Token<T>
Parameters: description: a human-readable label used in error messages. Does not need to be unique.
Returns: a Token<T>, usable with registerInstance, registerFactory and resolve.
interface IMailService {
send(to: string, body: string): Promise<void>;
}
const MailServiceToken = createToken<IMailService>('MailService');
Edge case
Two tokens created with the same description are still distinct registrations — identity is the underlying symbol, never the description string.
ServiceLifetime
enum ServiceLifetime {
Singleton,
Transient,
}
Only these two values exist. Singleton is the default used by registerFactory when no lifetime is given. See Lifetimes for the full explanation.
Container
| Method | Description |
|---|---|
registerInstance<T>(token, instance): void | Registers an already-created instance. Always Singleton. |
registerFactory<T>(token, factory, lifetime?): void | Registers a factory, built lazily. lifetime defaults to Singleton. |
resolve<T>(token): T | Resolves the service, fully typed. |
has(token): boolean | Checks whether a token is registered. |
remove(token): void | Removes a token's registration, if present. |
clear(): void | Removes every registration. |
registerInstance
registerInstance<T>(token: Token<T>, instance: T): void
Parameters: token: the service identifier; instance: the value returned on every resolution.
Returns: void.
Throws: RegistrationError if token is already registered.
registerFactory
registerFactory<T>(token: Token<T>, factory: (container: Container) => T, lifetime?: ServiceLifetime): void
Parameters: token: the service identifier; factory: builds the instance, receiving the container so it can resolve its own dependencies; lifetime: Singleton (default) or Transient.
Returns: void.
Throws: RegistrationError if token is already registered.
resolve
resolve<T>(token: Token<T>): T
Parameters: token: the service identifier to resolve.
Returns: the resolved instance, typed as T.
Throws: ResolutionError if unregistered; CircularDependencyError if resolving it requires resolving itself again, directly or transitively.
has / remove / clear
has(token: Token<unknown>): boolean
remove(token: Token<unknown>): void
clear(): void
remove on an unregistered token, and clear on an empty container, are both safe no-ops — neither throws.
Errors
Every error extends the abstract ContainerError, which carries the involved token (except CircularDependencyError, which additionally exposes the full cycle).
| Class | Thrown when | How to fix |
|---|---|---|
ContainerError | Abstract base class. Never thrown directly. | Catch it to handle any container error generically, via instanceof ContainerError. |
RegistrationError | Registering a token that is already registered. | Call remove(token) before re-registering it, or register the new implementation under a different token. |
ResolutionError | Resolving a token with no registration. | Check for a typo'd token reference, a missing registerInstance/registerFactory call, or a resolve() happening before registration runs. |
CircularDependencyError | Resolving a token that (transitively) depends on itself. | Read .path to see the exact cycle, then break it — extract the shared logic both services depend on into a third service, or resolve the dependency lazily inside the factory instead of eagerly at construction time. |
CircularDependencyError exposes the full cycle as .path (an array of the involved tokens) and renders it in .message as:
Circular dependency detected:
A
-> B
-> C
-> A