Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Inject an empty array with @injectAll() when nothing registered for the token #63

Open
paztek opened this issue Nov 16, 2019 · 13 comments · May be fixed by #64
Open

Inject an empty array with @injectAll() when nothing registered for the token #63

paztek opened this issue Nov 16, 2019 · 13 comments · May be fixed by #64
Assignees

Comments

@paztek
Copy link

paztek commented Nov 16, 2019

Is your feature request related to a problem? Please describe.
I'm using @injectAll('feature') to inject an array of Features into a Server. I'd like to unit test some of the mechanisms of the Server class but the resolve fails when zero feature has been registered on the container.

Description
Would it make more sense to inject an empty array with @injectAll() when no service has been registered on the container and the token is unknown by the container?

Alternate solutions
I tried @injectAll('feature') private readonly features?: Feature[] or @injectAll('feature') private readonly features: Feature[] = []but same error.

Additional context
By looking (quickly) at the code, it seems to be a one-line change at https://github.com/microsoft/tsyringe/blob/master/src/dependency-container.ts#L242 (apart from the tests) but maybe it breaks things or maybe it's not how it should behave.
I can try submitting a PR if that's OK with you.

@paztek
Copy link
Author

paztek commented Nov 16, 2019

Hum OK. I see.

That would introduce different behaviors for resolveAll()depending on whether the token is a string / symbol or a class and this may not be desirable.
And also a different behavior between resolve() and resolveAll() in case of unregistered token.

Is there a workaround for my use case ?

@paztek
Copy link
Author

paztek commented Nov 16, 2019

Here is the PR if you're interested: #64

@Xapphire13
Copy link
Collaborator

Xapphire13 commented Nov 25, 2019

I spoke briefly with @MeltingMosaic and we agreed that the default behaviour for non-registered resolutions should be to fail.

However, I can see a case where we would want to expose opt-in functionality to not fail if, and only if the target is an array or a nullable type. My best guess of how to opt-in would be a flag in the resolution options.

How does that sound?

@paztek
Copy link
Author

paztek commented Nov 25, 2019

Hi @Xapphire13,
Thanks for the answer.

If I understand correctly, you suggest something like this:
@injectAll({ resolveWithEmptyArrayOnNothingRegistered: true}) ...
Or a more global setting on the container ?

I think the Angular project solves this issue (cf APP_INITIALIZER, HTTP_INTERCEPTOR, etc.) with an additional @Optional() decorator or similar. That could be a way to do it too.

I’d be OK with both solutions.

@Xapphire13
Copy link
Collaborator

@paztek,

I was originally thinking of the first example (maybe with a name like optional or some variation). But I really like the decorator idea!

Do you have time to code up a PR?

@paztek
Copy link
Author

paztek commented Nov 27, 2019

@Xapphire13 I can try.
Just to be sure, should I try submitting a PR for:

  1. A @inject({ optional: true }) / @injectAll({ optional: true }) option
  2. A @optional() decorator ?

Intuitively, 1. seems easier to me.

@Xapphire13
Copy link
Collaborator

@paztek, could you give option 2 a stab? I assume the decorator would be on the parameters being injected right?

@MeltingMosaic
Copy link
Collaborator

I like the idea of an @optional() decorator. My concern with it is that it can create some odd behaviors where a service can have behavior that is different in the presence of another registration in the container. If however, the @optional() decorator is limited to array types (for injectAll), I think it's sensible. I know this deviates from Angular's implementation though.

@Xapphire13
Copy link
Collaborator

I think it would be safe to allow @optional to work with optional params also. However, we can scope the initial implementation just to array types and improve upon it in the future.

@AEPKILL
Copy link

AEPKILL commented Jan 19, 2020

I think it would be safe to allow @optional to work with optional params also. However, we can scope the initial implementation just to array types and improve upon it in the future.

Maybe @optional can provide a default value, like this @optional({ defaultValue: [] })

@SirBernardPhilip
Copy link

SirBernardPhilip commented Apr 26, 2021

Have there been any updates on this issue? The @optional({ defaultValue: whatever }) could be very helpful for a project I'm working on. I see there's a PR for what was discussed with arrays but not for this other more general enhancement.

Edit: I created my own PR which tries to implement this if it's any use to anyone.

@etiennenoel
Copy link

Totally agree with @SirBernardPhilip

@Welcius
Copy link

Welcius commented Feb 11, 2022

I ran into the same issue, @SirBernardPhilip's solution would be optimal for my use case. Any plans on merging it?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.

7 participants