joist icon indicating copy to clipboard operation
joist copied to clipboard

@joist/di: add multi providers.

Open deebloo opened this issue 1 year ago • 2 comments

And multi providers. This comes from frameworks like angular where you can provide multiple instances of a particular provider. They get returned as an array. There are some use cases where this can be very useful but it would make a number of things more complex and could potentially hurt performance.

NOTES: We would need a way to correctly type this. One option would be to have a separate inject and injectAll method. Would this go up the chain and find EVERY service instance marked as multi or only at the first level found. If we go with the injectAll method would we even need to mark an injectable as multi?

const PLUGINS = new StaticToken<string>('PLUGINS', { multi: true });

const app = new Injector({
  providers: [
    [
      PLUGINS, 
      [
        { factory: () => "first" }, 
        { factory: () => "second" }, 
        { factory: () => "third" }
      ]
    ],
  ]
})

app.inject(PLUGINS); // ["first"]
app.injectAll(PLUGINS); // ["first", "second", "third"]

Existing inject method will return the first multi item that was set. injectAll will always return an array. For services that are not defined as multi will always return an array with the single item in it. Internally we can keep ALL singletons in an array.

CHALLENGES:

At the moment the resolution algo short circuits when it finds a definition. For multi we would need to collect all instances up the dependency tree. An alternative COULD be to only allow one instance per injector but to collect them all the way up the tree rather than short circuiting

deebloo avatar Oct 22 '24 01:10 deebloo

I'm probably missing an actual use case, however currently I also only see additional complexity here. The last line of the code sample has a typo I guess:

const serviceArray = app.get(ServiceA); // [ServiceA, ServiceA]

At the moment this seems to be better handled by creating a composite service with interface ServiceA implementing an array of ServiceA

Phoscur avatar Dec 08 '24 13:12 Phoscur

An example use case would be plugins. If you had a program where you allowed plugins this would easily allow you to register multiple instances of plugins. This is what we did for ngxs back in the day with the angular dependency injector.

deebloo avatar Dec 08 '24 14:12 deebloo