Angular:如何为导入的模块提供对提供者的访问权限

时间:2018-02-02 23:04:41

标签: angular typescript

我有一个我编写的导入模块,它提供了一个带有可选依赖项的服务。事实上它恰好是可选的并不重要。这只是意味着我的应用程序没有出现错误。例如:

import { FooModule } from './foo.module';
import { BarService } from './bar.service';

// other imports and logic omitted...

@NgModule({
  declarations: [
    AppComponent,
  ],
  imports: [
    BrowserModule,
    FooModule.forRoot(options),
  ],
  providers: [
    BarService,
  ],
  bootstrap: [AppComponent],
})
export class AppModule { }

在上面的代码中,FooModule提供了FooService,我可以在我的应用中使用其他地方。 FooService具有可选的依赖关系:

export interface IBarService {
  bar: (x: string) => string;
}

export const BarService = new InjectionToken<IBarService>('any compatible bar service provider');

@Injectable()
export class FooService {

  constructor(
    @Optional() @Inject(BarService) private barService?: IBarService,
  ) {
    console.log(barService)
  }
}

我实际上在我的第一个代码块中提供了可选的依赖项(BarService)。然而,我发现它没有进入FooService内的FooModule

它们都具有相同的注射名称:BarService

然而,当我运行应用程序时,控制台会将barService记录为null

2 个答案:

答案 0 :(得分:0)

当我写这个问题时,我记得提供者的useExisting属性。我必须导入令牌(使用不同的变量名称),然后分配提供者。

import { FooModule, BarService as BarServiceForFoo } from './foo.module';
import { BarService } from './bar.service';

// other imports and logic omitted...

@NgModule({
  declarations: [
    AppComponent,
  ],
  imports: [
    BrowserModule,
    FooModule.forRoot(options),
  ],
  providers: [
    BarService,
    { provide: BarServiceForFoo, useExisting: BarService }
  ],
  bootstrap: [AppComponent],
})
export class AppModule { }

答案 1 :(得分:0)

  

它们都具有相同的注射名称:BarService

这一部分具有误导性,因为InjectionToken名称与调试无关。

此时它们是不同的令牌,除了开发人员的意图之外没有任何共同之处。 useExisting是一个选项,但它需要父项和所有其他模块依赖于BarService或者实现它依赖于Foo模块。

一个可能的解决方案是使用字符串标记,它很容易被反模式化,因为它提供了松散耦合和全局命名空间(这就是引入标记类的原因)但它符合当前的情况:

...
{ provide: 'vendorNamespace.BarService', useExisting: BarService }
...
...
constructor(
  @Optional() @Inject('appNamespace.BarService') private barService?: IBarService
) {}
...

另一个解决方案是使公共模块包含提供者令牌和接口......这是抽象类:

export abstract class BarService {
  abstract bar(x: string): string;
}
import { BarService as AbstractBarService } from 'common';
export class BarService implements AbstractBarService { ... }
import { BarService as AbstractBarService } from 'common';
import { BarService } from './bar.service';

...
{ provide: AbstractBarService, useClass: BarService }
...

这自然允许为提供者注入类型注释:

import { BarService } from 'common';

...
constructor(
  @Optional() private barService?: BarService
) {}
...