@Injectable
@Injectable registers a class so it can be resolved by inject. It records the class's scope, its providers, and an optional custom factory. A class that is never decorated cannot be injected - inject throws for it.
import { Injectable } from '@remotex-labs/xinject';
@Injectable()
class OrderService {}Options
@Injectable(options?) accepts an InjectableOptionsInterface:
| Option | Type | Default | Description |
|---|---|---|---|
scope | 'singleton' | 'transient' | 'transient' | Instance lifetime. See Scopes. |
providers | ProvidersType | - | Token registry resolved on demand when a parameter requests a token. |
factory | (...deps) => Instance | - | Replaces constructor instantiation. Receives the resolved arguments. |
const SQL = new InjectionToken<string>('SQL');
@Injectable({ scope: 'singleton', providers: [{ provide: SQL, useValue: 'SELECT 1' }] })
class Database {
constructor(@Inject(SQL) private sql: string) {}
}providers is a registry keyed by token, not an ordered argument list - entries are resolved only when a constructor parameter requests them through @Inject. See Providers for every provider form.
Custom factory
When a class needs creation logic beyond new, supply a factory. It receives the resolved constructor arguments in order and its return value becomes the instance.
@Injectable({
factory: (logger, metrics) => new MonitoredService(logger, metrics),
providers: [{ provide: LOGGER, useClass: LoggerService }, { provide: METRICS, useClass: MetricsService }]
})
class PaymentGateway {
constructor(@Inject(LOGGER) logger: Logger, @Inject(METRICS) metrics: Metrics) {}
}Where metadata lives
@Injectable stores its options on the class itself (via a private symbol), not in a shared module-level map. This keeps the container free of global state - see No global container. Only the class's own registration is used, so a subclass is not treated as injectable through inheritance.
Reading the registration
Use getInjectableOptions to read back what a class was registered with (or undefined if it was never decorated). Useful for tooling and tests.
import { getInjectableOptions } from '@remotex-labs/xinject';
getInjectableOptions(Database); // { scope: 'singleton', providers: [ ... ] }
getInjectableOptions(class {}); // undefinedApplying without decorator syntax
@Injectable is a plain function, so you can apply it directly when you are not using decorator syntax. Note that @Inject is a parameter decorator and does require decorator syntax on the constructor.
class Service {}
Injectable({ scope: 'singleton' })(Service);