I'm looking at the implementation of in-memory-web-api and there is the following code:
@Injectable()
export class InMemoryBackendService {
protected config: InMemoryBackendConfigArgs = new InMemoryBackendConfig();
^^^^^^
...
constructor(
@Inject(InMemoryBackendConfig) @Optional() config: InMemoryBackendConfigArgs
^^^^^^
) {
...
As I understand the pattern is the following:
If a user provides modified dependency through DI, it will be injected and the default one instantiated without DI will be overridden. I suspect something similar maybe with RequestOptions
in HTTP
module.
Is this a common pattern?
EDIT:
It turns out that in-memory-web-api
is not exactly the pattern I'm asking about. Suppose, I have a class A
that uses instance of class B
injectable with the token B
. So they are both registered with the root injector:
providers: [A, B]
Now, if a user wants to customize B
, he can register the customized version under the same token, thus effectively overrriding the original B
:
providers: [{provide:B, useClass: extendedB}]`
This is how RequestOptions
can be extended in http
module.
The default value isn't just overridden. The most important part here is
Object.assign(this.config, config || {})
Nothing would happen without it.
This pattern isn't specific to DI, it is a common recipe for default property values, similar to _.defaults
.
I would say that InMemoryBackendConfig
default implementation is useless abstraction here. Since this.config
is always merged with config
, the former could be just a plain object
protected config: InMemoryBackendConfigArgs = { ... };
InMemoryBackendConfig
and RequestOptions
use complicated variations of this pattern. Yes, in most basic form this is how this can be done:
providers: [{provide:B, useClass: extendedB}]`
This pattern is widely used by constant
services in AngularJS for configuration objects, but having B
as a class instead of plain object allows to extend the original values instead of replacing them.