Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Binding a class to an interface

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?

like image 612
Wilbert Avatar asked Aug 27 '15 16:08

Wilbert


People also ask

What is a bind interface?

You can bind the agent to specific interfaces on a host machine. This can be useful in situations where security is of high concern. For example, many enterprise networks use a gateway to separate the internal network from the Internet.

Why use interface?

Interfaces are useful for the following: Capturing similarities among unrelated classes without artificially forcing a class relationship. Declaring methods that one or more classes are expected to implement. Revealing an object's programming interface without revealing its class.

What is the purpose of an interface in java?

Interfaces are used in Java to achieve abstraction. By using the implements keyword, a java class can implement an interface. In general terms, an interface can be defined as a container that stores the signatures of the methods to be implemented in the code segment. It improves the levels of Abstraction.


2 Answers

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).
like image 127
Arnaud Boeglin Avatar answered Oct 05 '22 13:10

Arnaud Boeglin


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.

like image 8
Arun Kumar Avatar answered Oct 05 '22 12:10

Arun Kumar