Angular 2 可注入接口?

5
今天我遇到了一些我认为不会给我带来麻烦的事情。在Java和Spring中,我可以声明两个实现给定接口的bean,而在它们被注入的另一个类中,我只使用接口;这实际上是我喜欢控制反转的原因:你不需要真正知道你正在处理什么对象,只需要知道它的种类。因此,在我小小的Angular2/Typescript程序中,我也想做同样的事情:webapp.module.ts:
... 
import { WebAppConfigurationService } from './app/services/webapp.configuration.service';

@NgModule({
  ...
  providers: [WebAppConfigurationService]
})
export class AppModule { }

tnsapp.module.ts:

...
import { TnsConfigurationService } from './services/tns.configuration.service';

@NgModule({
   ...
   providers: [TnsConfigurationService]
})
export class AppModule { }

这两个模块使用不同的提供程序:TnsConfigurationServiceWebAppConfigurationService

然而,这两个@Injectable服务实现了相同的接口:

configuration.interface:

export interface IConfigurationService {
    ...
}

最后,在我的一个组件中,我使用了我在开始时向你展示的这些模块之一提供的可注入对象:

import { IConfigurationService } from './configuration.interface';

export class HeroesService {

    constructor(private configurationService: IConfigurationService) { }
}

我原本期望这个组件会被正确的服务注入,即使参数只明确定义了接口。当然,我收到了一个错误信息(“错误:无法解析HeroesService的所有参数”)。
现在,我并不指望有一个简单的解决方案,因为这听起来像是一种架构上的缺陷。但也许有人可以指出一个替代设计?

请查看 DI 文档 https://angular.io/docs/ts/latest/guide/dependency-injection.html#typescript-interfaces-aren-t-valid-tokens - yurzui
@yurzui 我喜欢它:“这不是Angular的错。” :-) 那好吧,或许还有一种优美的方法来做这件事...我稍后会阅读关于这个“OpaqueToken”的内容 - Sebas
OpaqueToken主要用于非类提供者(工厂和值)。 - Estus Flask
1个回答

8
为了让提供者被注入,它应该被注册为提供者。没有提供者。它不能成为一个提供者,因为接口在编译后的JS代码中不存在。
通常的做法是将被用作提供者标记的接口定义为抽象类。
abstract class ConfigurationService { ... }

@Injectable()
class WebAppConfigurationService extends ConfigurationService { ... }

...
providers: [{ provide: ConfigurationService, useClass: WebAppConfigurationService }]
...

这个配方通常被Angular 2本身所使用,例如抽象的NgLocalization以及具体的NgLocaleLocalization实现


这看起来非常不错,我明天早上(协调世界时)会及时向您通知。 - Sebas
这个对于Angular 4/5仍然适用吗?作为其他支持DI的语言(例如Java)的使用者,我发现使用抽象类作为提供者非常奇怪。 - Philip Feldmann
@PhilipFeldmann 是的,仍然非常相关。据我所知,TS及其接口对有Java背景的人来说看起来很奇怪,所以不足为奇。 - Estus Flask

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接