Closed anthonyma94 closed 1 year ago
TL;DR: No, it is not possible with CLASSIC
injection; it's somewhat possible with PROXY
and createContainer<YourCradleType>()
This was a design decision from the start.
The problems I have with Inversify and @inject(UserRepository)
are:
reflect-metadata
Additionally, interfaces are the most natural way to describe, well, an interface, and from what I can tell, in Inversify you don't get type safety when injecting interfaces (requires @inject(TYPES.UserRepository)
where TYPES
is a collection of symbols manually maintained. Therefore, the lack of type safety at this level in Awilix was acceptable due to what we gained.
In practice, you will rarely ever encounter type issues that you don't catch as you are writing/copy-pasting code, or with automated tests.
If you really feel that it's worth the trouble (some users do! I personally don't) you can use PROXY
injection + a cradle type.
interface Cradle {
userRepository: UserRepository // or IUserRepository if an interface!
}
const container = createContainer<Cradle>({ injectionMode: InjectionMode.PROXY })
// woah!
class Consumer {
constructor({ userRepository }: Pick<Cradle, 'userRepository'>) {}
}
// typed!
container.register({
userRepository: asClass(UserRepository),
consumer: asClass(Consumer)
})
// safe!
container.resolve('consumer')
Mind you, however, that CLASSIC
injection is probably the cleanest (no proxy magic) and it is also the most performant after the container is initialized. There is a slight overhead with the proxy (not significant), but worth mentioning.
I've been trying to switch from InversifyJS and this has been the best alternative so far! I'm trying to solve the problem of losing automatic type safety in the constructor.
In Inversify I would have something like this:
UserRepository
in inject is not a string, it is the class itself. I am mapping the class itself to the value, not a string representation of the class. That way it is very easy to make sure that 1) I am mapping the correct thing, and 2) any changes to the name of the class would throw errors at compile.I can't figure out how to get this assurance in Awilix.
register
forces me to use a string, and constructors param names don't have type checking. I also understand parameter decorators aren't a thing in TS 5.0 (part of the reason I'm switching). How do you recommend I go about this problem?