Fixing the "can’t resolve all parameters" error with Angular DI

How to fix the "can’t resolve all parameters" error with Angular

Fixing the "can’t resolve all parameters" error with Angular DI

The problem

Creating Angular services is something that I do often enough not to forget how. As I’ve explained in my last article, I usually prefer to define both an interface and an implementation for my services.

That allows me to inject the interface, thanks to an InjectionToken, but more importantly, to easily mock out the dependencies in my tests. I’m not saying that it’s impossible otherwise, but I find this approach much cleaner and simpler.

And this is exactly what I did, only to realize that there was a dependency injection error during application startup. Apparently, Angular couldn’t find my newly defined service. Weird since I just used the same usual approach.

Here’s what the error looked like:

Can’t resolve all parameters for QuillConfigurationDirective: [object Object], (?).

The (?) indicates that Angular couldn’t resolve the second parameter of the constructor:

As usual, I was using the injection token with the Inject decorator of Angular. Nothing out of the ordinary thus…

So I checked everything. Multiple times… But couldn’t find the cause.

My injection token was defined correctly, mapping a string to the type:

My service had the Injectable decorator set correctly:

A provider was correctly declared in my module’s forRoot static method:

And the forRoot method was correctly called in my app’s root module:

So what could it be??!

Well obviously the error lied in the above code examples.

A quick (bug ugly) workaround

After losing a bit of time trying to understand what the root cause was, I decided to try something else.

By removing the InjectionToken and simply using providedIn: root, the problem was indeed fixed.

But this was no solution, just a workaround.

Although, it gave me a hint: the problem really was at the level of the InjectionToken, whether on the “declaration” side, or on the injection side.

The root cause and correct solution

After googling a bit, I stumbled upon the following SO question, which (as usual) gave me the solution: it was an issue with the imports!

The error was indeed caused by the following imports in my core module:

import { CORE_QUILL_EDITOR_CONFIGURATION_SERVICE } from '@app/core';
import { QuillEditorConfigurationServiceImpl } from '@app/core';

The thing is that elements within a module should use relative imports for elements that are part of the same module; they should never import through the module’s public API barrel (or barrels in general btw).

The problem with that import is that if something that depends on the service is loaded first in the barrel (directly or not), then the DI system will fail since the service has not been declared yet and thus can’t be resolved…

I’ve been bitten quite a few times with incorrect auto imports and, more generally, barrels. It’s no wonder that the Angular team is not so fond of barrels anymore (afaik).

So in the end, the fixed imports were simply relative ones:

import { CORE_QUILL_EDITOR_CONFIGURATION_SERVICE } from './services/quill-editor-configuration.service.constants';
import { QuillEditorConfigurationServiceImpl } from './services/quill-editor-configuration.service';

From that point on, no more injection issue! Phew.

Note that this solution might not work in all cases. If you have a circular dependency between two elements, then the solution might instead by to use a forwardRef.

Conclusion

In this article, we’ve seen how insidious import problems can be, creating difficult to understand issues like this one.

My general advice is to be very careful with imports and barrels in general. Don’t blindly trust your IDE; unfortunately sometimes it creates issues by importing elements from barrels when it shouldn’t.

That's it for today! ✨