Binding a class to an interface
To make it short the problem is that Interfaces disappear when typescript is compiled. So you'd have to use @Inject with a string.
Or there's another option, if you check the last article of Victor Savkin you can find this in the comments :
Some background. In TypeScript, interfaces are structural and are not retained at runtime. So you have to use ILoginService as follows:
constructor(@Inject("ILoginService") s:ILoginService).
You don't have to use a string - any object can be passed in there. We actually provide an object called OpaqueToken that can be used for this purpose.
interface ILoginService { login(credentials);}const ILoginService = new OpaqueToken("LoginService");
can be used like this:
constructor(@Inject(ILoginService) s:ILoginService).
I dont know if it is possible with interface as interface will not be available at runtime (javascript does not know about interface).But it can be done using abstract classes.
//abstract-parent-service.ts
export class DatabaseService{ getService: ()=>string;}
//hibernate.service.ts
import {DatabaseService} from "./abstract-parent-service";export class HibernateService implements DatabaseService{ constructor() { } getService() { return "i am hibernate"; }}
//jdbc.service.ts
import {DatabaseService} from "./abstract-parent-service";export class JDBCService implements DatabaseService{ constructor() { } getService() { return "i am Jdbc"; }}
//cmp-a.component.ts
import {DatabaseService} from "./abstract-parent-service";import {HibernateService} from "./hibernate.service";@Component({ selector: 'cmp-a', template: `<h1>Hello Hibernate</h1>`, providers: [{provide: DatabaseService, useClass: HibernateService}]})export class CmpAComponent { constructor (private databaseService: DatabaseService) { console.log("Database implementation in CompA :"+this.databaseService.getService()); }}
//cmp-b.component.ts
import {DatabaseService} from "./abstract-parent-service";import {HibernateService} from "./hibernate.service";@Component({ selector: 'cmp-b', template: `<h1>Hello Jdbc</h1>`, providers: [{provide: DatabaseService, useClass: JDBCService}]})export class CmpAComponent { constructor (private databaseService: DatabaseService) { console.log("Database implementation in CompA :"+this.databaseService.getService()); }}
But the problem with this implementation is HibernateService and JDBCService are not able to extend any other class now because they have already got married with DatabaseService.
class A{ constructor(){ console.log("in A"); }}class B extends A{ constructor(){ super(); console.log("in B"); }}class C extends A{ constructor(){ super(); console.log("in C"); }}let c = new C();//This thing is not possible in typescriptclass D extends B, C{//error: Classes can only extend a single class constructor(){ super();// which constructor B or C console.log("in D"); }}
If you are using this pattern for DI, make it sure that your child class services are not going to extend any other functionality in future.