Binding a class to an interface

拈花ヽ惹草 提交于 2019-12-18 10:34:34

问题


Using typescript, I can easily bind classes to themselves:

bootstrap(MyAppComponent, [MyClass]);

However, I would like to bind my class to an interface, like such:

boostrap(MyAppComponent, [???]);

such that I can inject it as follows:

class MyAppComponent {
    constructor(my_class : IMyClass){
    }
};

Is this possible in Angular2? If yes, how to I have to specify the binding?


回答1:


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).



回答2:


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 typescript
class 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.



来源:https://stackoverflow.com/questions/32254952/binding-a-class-to-an-interface

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!