14
votes

In my Angular 9 app, I have an abstract class:

export abstract class MyAbstractComponent {
  constructor(
    protected readonly cd: ChangeDetectorRef,
  ) {
    super();
  }

  // ...
}

and a Component extending it:

@Component({
  // ...
})
export class MyConcreteComponent extends MyAbstractComponent {
  // ...
}

Everything works fine except the tests, where I get the following error:

Error: This constructor is not compatible with Angular Dependency Injection because its dependency at index 0 of the parameter list is invalid. This can happen if the dependency type is a primitive like a string or if an ancestor of this class is missing an Angular decorator.

Please check that 1) the type for the parameter at index 0 is correct and 2) the correct Angular decorators are defined for this class and its ancestors.

9

9 Answers

9
votes

We faced the same issue when migrating to version 9. At the end we found out we forgot to add decorators to some abstract components. As of v9 all classes that uses Angular DI must have an Angular class-level decorator.

Example from Ivy compatibility examples:

Before:

export class DataService {
  constructor(@Inject('CONFIG') public config: DataConfig) {}
}

@Injectable()
export class AppService extends DataService {...}

After:

@Injectable() // <--- THIS
export class DataService {
  constructor(@Inject('CONFIG') public config: DataConfig) {}
}

@Injectable()
export class AppService extends DataService {...}
8
votes

Took me a while, but after creating a new application with angular 10.2.3 my base tsconfig.json did not have the

"emitDecoratorMetadata": true,

in the compilerOptions!

After adding that again to the tsconfig.json, DI worked as expected.

7
votes

I've resolved my issue by adding the constructor in MyConcreteComponent and calling the super(...) constructor:

@Component({
  // ...
})
export class MyConcreteComponent extends MyAbstractComponent {

  // adding this block fixed my issue
  constructor(
    protected readonly cd: ChangeDetectorRef,
  ) {
    super(cd);
  }

  // ...
}
6
votes

In my case simple restarting npm fixed this error.

1
votes

Today I had to face this exact error while performing tests in my app using Jest. Running Angular 10.2, I had another spec file that was performing the exact same test without throwing any error. Every class had the decorators. Took me an hour to find out the problem: I had a circular dependency in my test file, and I didn't notice it since tests were not displaying usual Angular warning.

So just to point out to somebody else that stumble in the same problem, check your imports!

1
votes

I got something close to this error message ("Error: This constructor was not compatible with Dependency Injection.") when I inadvertently changed an import statement to an import type statement:

WRONG

import type { AngularFirestore, AngularFirestoreDocument } from '@angular/fire/firestore'

@Injectable({
  providedIn: 'root'
})
export class CommentsApiService {

  constructor(
    private firestore: AngularFirestore
  ) { }

  // ...
}

CORRECT

import { AngularFirestore } from '@angular/fire/firestore'
import type { AngularFirestoreDocument } from '@angular/fire/firestore'

@Injectable({
  providedIn: 'root'
})
export class CommentsApiService {

  constructor(
    private firestore: AngularFirestore
  ) { }

  // ...
}
1
votes

In my case it happened because I was in git repository A and moved to another git repository (B) and some services which existed in repository A was no longer on B. so, by simple restarting npm this error disappeared. Hope it works for others.

0
votes

in my exact case(in angular9), By adding private accessor to the constructor parameter..

0
votes

In my case I had a constructor argument that the di container didn't recognize. I marked it optional which was good enough for it to ignore it:

import { Optional } from '@angular/core';    

constructor(protected coolService: CoolService, @Optional() private name: string) {...