2

I'm trying to use Angular2 dependency injection but get the following error message:

error NG2003: No suitable injection token for parameter 'service' of class 'PaymentService'

app.module.ts - provider with factory method

@NgModule({
  declarations: [
    AppComponent
  ],
  imports: [
    BrowserModule
  ],
  providers: [
    PaypalPayment,
    CardPayment,
    {
      provide: PaymentService,
      useFactory: () => {
        return new PaymentService(new PaypalPayment());
      }
    }
  ],
  bootstrap: [AppComponent]
})
export class AppModule {
}

payment.service.ts - injectable payment service

@Injectable()
export class PaymentService {

  constructor(private service: Payment) {
  }

  pay(amount: number) {
    console.log('Payment Service -> pay(...) is running');
    this.service.pay(amount);
  }
}

payment.interface.ts, card-payment.ts, paypal-payment.ts files

export interface Payment {
  pay(amount: number);
}

@Injectable()
export class CardPayment implements Payment {
  pay(amount: number) {
    console.log('Paid by card. Amount=', amount);
  }
}

@Injectable()
export class PaypalPayment implements Payment {
  pay(amount: number) {
    console.log('Paid via Paypal. Amount=', amount);
  }
}

Note: Everything works fine if I replace the interface "Payment" in PaymentService file with one of its implementations (PaymalPayment or CardPayment). But it's a pretty common case to have an interface there.

The full source code is here

  1. git clone https://github.com/karenmargaryan/di-via-interfaces-issue
  2. cd di-via-interfaces-issue
  3. npm install
  4. ng serve

1 Answer 1

2

In payment.service.ts :

Update the Constructor

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

constructor(@Inject(Payment) private service: Payment)
Sign up to request clarification or add additional context in comments.

5 Comments

Your version is working. Thank you very much for your reply. But do you understand what is the problem with my version? I even found an example like I wrote in Ari Lerner's book, but his version also doesn't work.
Sure, you're welcome. In order to inject service in a constructor, the service type should be decorated as @Injectable() and this is usually done when you use "ng g s" CLI command. In your case you are trying to inject the service of type Payment while Payment is not decorated as @Injectable() so you should do manual injection by @Inject() . If you found the answer beneficial, do not forget to mark the answer as accepted :)
I agree with you about decorator, but there is an exception here. If I don't create an instance of "Payment" (it's an interface), and I inject something there, then why shall I decorate with "Injectable()". If you just replace the interface with base class (without decorator), it will work perfectly. And as I understand that is against your answer. Am I right? So the main secret here is why this works with "class Payment" and doesn't work with "interface Payment"... Anyway thank you for your effort and explaination .
@Inject decorator is only needed for injecting primitives. The primitive types are number, string, boolean, bigint, symbol, null, undefined, or object. In your case, the interface is considered primitive so it required this decorator.
I skipped this answer at first because I thought there was no way this would be a reasonable fix, but it worked perfectly for me. Thanks!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.