A class gets its dependencies through its constructor. At registration you list a token for each constructor
parameter, in the same order. When the class is resolved, the container resolves each token and passes the
results as arguments.
Registers a scoped service: one instance per scope. Same forms as
addSingleton
.
addScoped(
classOrderService
OrderService, [
classDatabase
Database,
constLogger:InjectionToken<Logger>
Logger]);
There are no decorators and no metadata: the array is the whole contract. It is also the only place where a service
mentions the container, and the class itself stays a plain class you can construct in a test.
The dependency array is typed from the constructor: each position expects a token for the parameter at that
position. A typed token (createToken<T>()) whose type doesn’t fit the parameter is rejected, and so is an array
that is too short:
Registers a scoped service: one instance per scope. Same forms as
addSingleton
.
addScoped(
classOrderService
OrderService, [
constLogger:InjectionToken<Logger>
Logger,
classDatabase
Database]); // Logger token where a Database goes
Error ts(2769) ― No overload matches this call.
Overload 3 of 5, '(token: Token<OrderService>, implementation: Newable<NoInfer<OrderService>, []>): ServiceCollection', gave the following error.
Argument of type '(InjectionToken<Logger> | typeof Database)[]' is not assignable to parameter of type 'Newable<NoInfer<OrderService>, []>'.
Type '(InjectionToken<Logger> | typeof Database)[]' provides no match for the signature 'new (): NoInfer<OrderService>'.
Registers a scoped service: one instance per scope. Same forms as
addSingleton
.
addScoped(
classOrderService
OrderService, [
classDatabase
Database]); // one token short
Error ts(2769) ― No overload matches this call.
Overload 1 of 5, '(token: Token<OrderService>, factory: ServiceFactory<NoInfer<OrderService>>): ServiceCollection', gave the following error.
Argument of type '(typeof Database)[]' is not assignable to parameter of type 'ServiceFactory<NoInfer<OrderService>>'.
Type '(typeof Database)[]' provides no match for the signature '(provider: ServiceProvider, key?: ServiceKey | undefined): NoInfer<OrderService> | Promise<NoInfer<OrderService>>'.
Overload 2 of 5, '(token: Newable<OrderService, [db: Database, logger: Logger]>, dependencies: readonly [db: Token<Database>, logger: Token<Logger>]): ServiceCollection', gave the following error.
Argument of type '[typeof Database]' is not assignable to parameter of type 'readonly [db: Token<Database>, logger: Token<Logger>]'.
Source has 1 element(s) but target requires 2.
Overload 3 of 5, '(token: Token<OrderService>, implementation: Newable<NoInfer<OrderService>, []>): ServiceCollection', gave the following error.
Argument of type '(typeof Database)[]' is not assignable to parameter of type 'Newable<NoInfer<OrderService>, []>'.
Type '(typeof Database)[]' provides no match for the signature 'new (): NoInfer<OrderService>'.
The check works for every form that takes a class and a dependency array: add*(Class, deps),
add*(token, Impl, deps), tryAdd*, the keyed methods and replace. It also checks that the implementation
fits the token: addSingleton(Logger, Database) fails because a Database is not a Logger.
Registers a scoped service: one instance per scope. Same forms as
addSingleton
.
addScoped(
classReports
Reports, [
classMailer
Mailer,
classClock
Clock]);
Error ts(2769) ― No overload matches this call.
Overload 3 of 5, '(token: Token<Reports>, implementation: Newable<NoInfer<Reports>, []>): ServiceCollection', gave the following error.
Argument of type '(typeof Clock | typeof Mailer)[]' is not assignable to parameter of type 'Newable<NoInfer<Reports>, []>'.
Type '(typeof Clock | typeof Mailer)[]' provides no match for the signature 'new (): NoInfer<Reports>'.
TypeScript also compares types structurally, so two typed tokens whose types have the same shape are interchangeable.
The parameter types are inferred from the implementation. If you pass the service type explicitly, the
remaining type parameter falls back to any[] and the array is no longer compared with the constructor:
// Compiles, and fails at runtime with the wrong arguments.
Registers a scoped service: one instance per scope. Same forms as
addSingleton
.
addScoped<
classOrderService
OrderService>(
classOrderService
OrderService, [
constLogger:InjectionToken<Logger>
Logger,
classDatabase
Database]);
Let TypeScript infer. If a token needs a type, put it on the token (createToken<Logger>('Logger')), not on the call.
Code migrated from @nodelibraries/ioc, which needed addSingleton<ILogger>(...), should drop those type
arguments; see Migrating.
At runtime the container compares the number of tokens with the constructor’s declared parameter count
(Function.length). Too few tokens throw a RegistrationError from the add* call itself, at startup, instead of
creating a half-initialised object later:
Registers a scoped service: one instance per scope. Same forms as
addSingleton
.
addScoped(
classOrderService
OrderService);
} catch (
var error:unknown
error) {
var console:Console
The console module provides a simple debugging console that is similar to the
JavaScript console mechanism provided by web browsers.
The module exports two specific components:
A Console class with methods such as console.log(), console.error() and console.warn() that can be used to write to any Node.js stream.
A global console instance configured to write to process.stdout and
process.stderr. The global console can be used without importing the node:console module.
Warning: The global console object's methods are neither consistently
synchronous like the browser APIs they resemble, nor are they consistently
asynchronous like all other Node.js streams. See the note on process I/O for
more information.
Example using the global console:
console.log('hello world');
// Prints: hello world, to stdout
console.log('hello %s', 'world');
// Prints: hello world, to stdout
console.error(newError('Whoops, something bad happened'));
// Prints error message and stack trace to stderr:
// Error: Whoops, something bad happened
// at [eval]:5:15
// at Script.runInThisContext (node:vm:132:18)
// at Object.runInThisContext (node:vm:309:38)
// at node:internal/process/execution:77:19
// at [eval]-wrapper:6:22
// at evalScript (node:internal/process/execution:76:60)
// at node:internal/main/eval_string:23:3
constname='Will Robinson';
console.warn(`Danger ${name}! Danger!`);
// Prints: Danger Will Robinson! Danger!, to stderr
Example using the Console class:
constout=getStreamSomehow();
consterr=getStreamSomehow();
constmyConsole=new console.Console(out, err);
myConsole.log('hello world');
// Prints: hello world, to out
myConsole.log('hello %s', 'world');
// Prints: hello world, to out
myConsole.error(newError('Whoops, something bad happened'));
// Prints: [Error: Whoops, something bad happened], to err
Prints to stdout with newline. Multiple arguments can be passed, with the
first used as the primary message and all additional used as substitution
values similar to printf(3)
(the arguments are all passed to util.format()).
A registration is invalid (e.g. a constructor needs more dependencies than were given).
RegistrationError); // true
// 'OrderService' has 1 constructor parameter(s) but 0 dependency token(s) were given for 'OrderService'. …
}
This is the safety net for JavaScript code and for explicit <T> calls, where the compiler doesn’t help.
Function.length stops at the first parameter with a default value and doesn’t count rest parameters, so those
parameters may be left out of the array.
Whether a dependency is registered is only known once the collection is complete. By default it is checked when
the service is resolved, and a missing one throws ServiceNotFoundError with the path that needed it
(No service registered for 'Logger' (required by OrderService).). Pass validateOnBuild: true to
buildServiceProvider to check every registration up front instead; see Validation.
The container tells implementations and factories apart by syntax. A function written with class is constructed
with new and receives its dependencies. Any other function, an arrow or a function declaration, is a
factory and is called as factory(provider, key).
Registers a singleton: one instance for the root provider and all its scopes.
addSingleton(Class) / addSingleton(Class, [deps]): the class is its own token.
addSingleton(token, Implementation, [deps]): deps are checked against the constructor's parameters.
addSingleton(token, (provider) => instance): a factory, may be async.
addSingleton('mailer2', () =>new
constructor Mailer(): Mailer
Mailer()); // arrow: called as a factory
Factories take no dependency array: they resolve what they need from the provider they receive. Their dependencies
are therefore invisible to the compile-time check, to validateOnBuild and to the
diagnostics. Prefer a class with a dependency array where you can.