-
-
Notifications
You must be signed in to change notification settings - Fork 8.1k
Description
Is there an existing issue for this?
- I have searched the existing issues
Current behavior
Imagine a situation where there are N modules with providers MyService1, MyService2, ..., MyServiceN (one provider per module), the providers are all default-scoped and registered under the same token MY_SERVICE.
When I attempt to resolve all instances with
moduleRef.resolve(MY_SERVICE, undefined, { strict: false, each: true })I receive an array with N items: [MyServiceN {}, MyServiceN {}, ..., MyServiceN {}] (the particular provider depends on the order of imports in AppModule).
In the production code, some of the providers are request-scoped, which is why I needed to use ModuleRef.resolve() and ModuleRef.get() would not work (although it works fine for this example with only default-scoped providers).
Minimum reproduction code
https://github.com/hajekjiri/nestjs-same-token-multiresolution
Steps to reproduce
npm installnpm test
Expected behavior
Given the described situation and the resolve call
moduleRef.resolve(MY_SERVICE, undefined, { strict: false, each: true })I would expect to receive an array with all of the providers: [MyService1 {}, MyService2 {}, ..., MyServiceN {}].
NestJS version
11.1.9
Packages versions
{
"scripts": {
"test": "jest",
"test:debug": "node --inspect-brk node_modules/.bin/jest --runInBand --no-cache --detectOpenHandles --forceExit app.test.ts"
},
"dependencies": {
"@nestjs/common": "^11.1.9",
"@nestjs/core": "^11.1.9",
"@nestjs/platform-express": "^11.1.9",
"reflect-metadata": "^0.2.2",
"rxjs": "^7.8.2"
},
"devDependencies": {
"@nestjs/testing": "^11.1.9",
"@types/jest": "^30.0.0",
"jest": "^30.2.0",
"ts-jest": "^29.4.5",
"typescript": "^5.9.3"
}
}Node.js version
22.17.0
In which operating systems have you tested?
- macOS
- Windows
- Linux
Other
The issue lies in this condition (AbstractInstanceResolver), which always passes for default-scoped providers, then leads to this line (InstanceLinksHost) and always returns the last provider in the array (always the same one).
I came up with two ideas to fix this issue, none of which breaks any existing tests. Let me know what you think and I'll gladly submit a PR.
Proposal 1: Add && !options?.each to the condition
if (wrapperRef.isDependencyTreeStatic() && !wrapperRef.isTransient && !options?.each) {
// ...
}This would force multiresolution to go through the other code path (intended for request-scoped and transient-scoped providers), which resolves all providers just fine.
Proposal 2: Return instance from wrapper directly
Not sure what this could affect, but in case the condition passes, we could replace the return statement
return this.get(typeOrToken, { strict: options?.strict });with
return wrapperRef.instance;and return the instance directly from the wrapper.
I think we might also have to extend the condition to check if the instance was successfully resolved in the wrapper.