Skip to content

inject & forceInject

inject

inject(token, ...args) resolves and constructs a class registered with @Injectable. It:

  1. Returns the cached instance if the class is a resolved singleton.
  2. Reads the class's registration - throwing if it was never decorated.
  3. Resolves each @Inject parameter from the class's providers registry.
  4. Constructs the class (or calls its factory), caching the result when the scope is singleton.
ts
import { inject, Injectable } from '@remotex-labs/xinject';

@Injectable()
class Service {}

const instance = inject(Service); // instanceof Service

Injecting dependencies

Each constructor parameter declares its dependency with @Inject:

ts
@Injectable()
class Database {}

@Injectable()
class UserService {
    constructor(@Inject(Database) public db: Database) {}
}

inject(UserService).db; // a Database instance

Overriding arguments

Arguments passed to inject fill undecorated parameters and take precedence over the @Inject token at each position:

ts
@Injectable()
class Logger {}

@Injectable()
class Service {
    constructor(@Inject(Logger) public logger: Logger) {}
}

const stub = new Logger();
inject(Service, stub).logger === stub; // true

Errors

inject throws when the class was not registered:

ts
class NotRegistered {}

inject(NotRegistered); // throws: Cannot inject NotRegistered - not marked @Injectable

It also throws when a requested InjectionToken has no provider (No provider for InjectionToken(...)), and when it detects a dependency cycle.

forceInject

forceInject(token, ...args) behaves like inject but first drops any cached singleton for the class, so a fresh instance is always built (and, for a singleton, becomes the new cached instance).

ts
import { inject, forceInject, Injectable } from '@remotex-labs/xinject';

@Injectable({ scope: 'singleton' })
class Service {}

const first = inject(Service);
const fresh = forceInject(Service);

fresh === first;          // false - a new instance was built
inject(Service) === fresh; // true  - the cache now holds the fresh instance

Use it to reset a singleton's state (for example, between tests, or after a configuration change). It replaces only the target class's cached instance, not those of its dependencies.

Type inference

inject is fully typed: the return type is the instance type of the token, and the variadic args are typed against the constructor's parameters.

ts
@Injectable()
class Api {
    constructor(public url: string) {}
}

const api = inject(Api, 'https://example.com'); // api: Api

Released under the Mozilla Public License 2.0