-
Notifications
You must be signed in to change notification settings - Fork 159
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
Add @injectOptional() to handle optional constructor args #182
Comments
Yeah, this has come up a time or two. Both Inversify and Angular implement it as well. I have been reticent to follow suit, because one thing I have always liked about DI is that there is a guarantee that either you get all of your parameters or you fail to resolve. Still, if people are performing workarounds like you have above, it seems sensible to allow users to opt into an optional resolution. I'd at least look at a PR for this. |
I have extended @willieseabrook solution by introducing a custom decorator
Now we can use this decorator inside the constructors
|
I came up with this solution to overcome the coupling with the root container abusing factory providers a little bit: Full example: container.register("TransientContainer", { useFactory: (c) => c });
@injectable()
class Optional {
constructor(
@inject("TransientContainer")
private readonly container: DependencyContainer,
) {}
getOptionalValue(token: InjectionToken): unknown {
try {
return this.container.resolve(token);
} catch (e) {
return null;
}
}
}
class OptionalTransform {
public transform(optional: Optional, token: InjectionToken): unknown {
return optional.getOptionalValue(token);
}
}
function injectOptional(token: InjectionToken) {
return injectWithTransform(Optional, OptionalTransform, token);
}
const childA = container.createChildContainer();
const childB = container.createChildContainer();
childA.register("Bar", { useValue: "my bar" });
const barA = childA.resolve(Foo).bar; // my bar!
const barB = childB.resolve(Foo).bar; // null I am a little wary of the implications of calling |
Is your feature request related to a problem? Please describe.
I'm about 2 days in to using tsyringe so I might be totally lost, but I can't see how to support optional constructor parameters out of the box.
If you look at the constructor above, config? is optional, and this is something the logic of my class expects.
However, if I do not register 'MyOptionalService', tsyringe will throw an error that it could not find a registration for 'MyOptionalService'
The logic of my code is that sometimes 'MyOptionalService' would be registered, sometimes it would not be registered.
Alternate solutions
My workaround is to hack with @injectWithTransform.
This is verbose.
And will (I think) only work with the global container, where as I am using child containers.
Then:
Proposed Solution
Add @injectOptional() so that the following would work:
@injectOptional would not throw an error if the 'MyOptionalService' is not registered, instead it would simply inject undefined.
Additional context
Inversify supports this feature. Just because that supports it doesn't mean tsyringe should, but it is an example implementation of how other people have approached this feature.
https://github.com/inversify/InversifyJS/blob/master/wiki/optional_dependencies.md
The text was updated successfully, but these errors were encountered: