web-dev-qa-db-ja.com

クラスをインターフェースにバインドする

TypeScriptを使用すると、クラスを自分自身に簡単にバインドできます。

bootstrap(MyAppComponent, [MyClass]);

ただし、次のように、クラスをインターフェイスにバインドしたいと思います。

boostrap(MyAppComponent, [???]);

次のように注入できるように:

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

これはAngular2で可能ですか?はいの場合、どのようにバインディングを指定する必要がありますか?

26
Wilbert

簡単に言うと、問題はTypeScriptがコンパイルされるとインターフェイスが消えることです。したがって、文字列で@Injectを使用する必要があります。

または、別のオプションがあります。 Victor Savkinの最後の記事 をチェックすると、コメントでこれを見つけることができます。

いくつかの背景。 TypeScriptでは、インターフェースは構造的であり、実行時に保持されません。したがって、次のようにILoginServiceを使用する必要があります。

constructor(@Inject("ILoginService") s:ILoginService).

文字列を使用する必要はありません-任意のオブジェクトをそこに渡すことができます。実際に、この目的で使用できるOpaqueTokenというオブジェクトを提供しています。

interface ILoginService { login(credentials);}
const ILoginService = new OpaqueToken("LoginService");

このように使用できます:

constructor(@Inject(ILoginService) s:ILoginService).
26
Arnaud Boeglin

実行時にインターフェイスが使用できないため、インターフェイスでそれが可能かどうかはわかりません(JavaScriptはインターフェイスを認識していません)。しかし、抽象クラスを使用して行うことができます。

//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());
    }
}

ただし、この実装の問題はHibernateServiceとJDBCServiceが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");
    }
}

このパターンをDIに使用している場合は、子クラスサービスが将来的に他の機能を拡張しないことを確認してください。

8
Arun Kumar