Comments (3)
Hi!
Actually I don't like this design myself, but here's the problem I can't solve:
class MyChild {
constructor(someService: SomeService: otherThing: OtherThing) {
/* ... */
}
}
const TOKENS = {
someService: token<SomeService>('SomeService'),
myChildFactory: token<Factory<MyChild, [dep: OtherThing]>>('Factory<MyChild>')
};
injected(MyChild, TOKENS.someService, /* ??? */);
const container = new Container();
container.bind(TOKENS.myChildFactory)
.toFactory(MyChild, (dep: OtherThing): MyChild => new MyChild(/* ??? */, dep));
I mean, the problems start when you need to combine injected arguments and external ones.
It might look like:
container.bind(TOKENS.myChildFactory)
.toFactory(
MyChild,
(dep: OtherThing): MyChild => new MyChild(container.get(TOKENS.someService), dep),
);
but I don't think it's the best design. What do you think?
from brandi.
Sorry for the delayed response, I keep meaning to sit down and give this the attention it deserves. The bottom example is something that I'm actually using in some of my code currently, and while it sorta works there are several issues with it.
- Currently, as far as I can tell, the constructing container is not supplied to the factory, so you have to rely on inherited scope. That makes it very difficult to use factories that are not in the binding file itself, leading to that file blowing out.. unless you then inject the container, which is a whole different mess.
- It means that container aware factories are not really viable for use in dependency modules, as they will have no idea of the container they are being used from within. (ran into this one today)
- This method also requires that you either hard code the tokens, or inject them. That gets really really cumbersome, especially if you're using this to build factories for a library.
- It leads to a lot of not-so-DRY code which (while not exactly unusual for the construction layer) is annoying.
- I'm not sure how it would live alongside the initialization pattern that is currently in place. I'm not a huge fan of that pattern as a default, but it definitely solves some problems with objects that don't support constructor injection.
I think there are a few potential things that could help in all of this:
- Supply the calling container to the factory at call time. I like this better than injecting it into an instance of the factory, as it allows child container bindings to be used, even if the factory was bound to a parent container or dependency module.
- Create something that acts as something between a factory and a container, in that it allows you to supply temporary bindings for use in a normal resolution request down the line.
- Add a
runtime
token type that specifies that the dependency will be supplied at runtime instead of being a registered token
So numbers 2 and 3 might look something like this
// [...]
injected(MyChild, TOKENS.someService, RuntimeToken('otherThing'), RunTimeToken('anotherOtherThing'));
const MyChildBindingResolver: BindingResolver<OtherThing, OtherThing> = (thing1: OtherThing, thing2: OtherThing) => { 'otherThing' : thing1, 'anotherOtherThing': thing2 };
// Potential binding syntax 1
container.bind(TOKENS.myChildFactory)
.withBindingSource(MyChildBindingResolver)
.toFactory(MyChild, Factory<MyChild>) ; // unsure if this signature would need to change
// Potential binding syntax 2
container.bind(TOKENS.myChildFactory)
.toFactory(MyChild, Factory<MyChild, [thing1: OtherThing, thing2: OtherThing]>, MyChildBindingResolver);
The idea being that you'd call the factory with arguments, but it'd pass those arguments to the binding resolver... though looking at it, that resolver might not be necessary if we are using the factory tuple with a Runtime token?
I'm reaching the edges of my TypeScript knowledge with this one, sorry... it's just a bit of functionality that is common in the DI systems I've used in other languages.
Thanks regardless!
from brandi.
just bumping, any movement on this?
from brandi.
Related Issues (12)
- Add async factories support HOT 3
- Calling injected with a token instead of constructor HOT 2
- Please update react types HOT 1
- Unable to get instance at runtime - what am i missing? HOT 4
- Accept token factories as arguments to `injected` HOT 2
- Injected not working when disabled strictNullChecks HOT 1
- Array Injections HOT 4
- DIP Violation HOT 2
- Differences with ditox HOT 3
- [Question] Navigate to binding in VSCode
- Compilation error with TypeScript 4.9.5
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from brandi.