定义全局 TypeScript 配置(接口),用于 Aurelia 依赖注入



在Aurelia中,我有几个依赖于相同配置的类。使用 IoC/DI,此配置可以作为构造函数参数提供似乎是很自然的。例如:

@autoinject
export class CustomerService {
constructor(config: IRemoteServiceConfig) {
}
}
@autoinject
export class GummyBearService {
constructor(config: IRemoteServiceConfig) {
}
}

在最简单的示例中,IRemoteServiceConfig可能看起来像这样(为简洁起见,删除了其他内容(:

export IRemoteServiceConfig {
endpoint: string;
apiKey?: string;
// etc. several other settings
}

将配置注入构造函数非常适合测试,并且不需要我读取每个类中的配置和设置。

这些服务依赖于相同的配置,我想在我的应用程序中定义一次 - 在启动期间 - 定义一次

通读有关依赖注入的Aurelia文档,我看到有几种方法可用于此目的,例如registerInstance()registerResolver()registerSingleton()。文档确实缺乏一些关于如何以及在何处定义这一点的上下文。

我从启动例程的configure()部分中的以下内容开始:

// register a static config; for brevity these are hardcoded settings
// but could come from anywhere
container.registerSingleton(IRemoteServiceConfig, () => {
return <IRemoteServiceConfig> {
endpoint: 'http://foo.com/api/v23/',
apiKey: 'abc'
}
});

它似乎没有拾取任何东西(没有错误(。但这也可能只是我对如何初始化容器的无知。

的问题:我如何以及在哪里可以在Aurelia中定义IRemoteServiceConfig(如果有的话(,以便一旦DI启动服务,它就会自动拾取我的(硬编码(配置?

请注意,在这个SO问题中提到"它不能与接口一起使用,因为TypeScript在运行时编译了这些接口。这个问题也是+2年前的,无论是在Aurelia还是在TypeScript中,都发生了很大的变化。无论情况是否仍然如此,同样的问题也适用于类的实例而不是接口。

另请注意,我知道诸如aurelia-configuration之类的库,它们似乎适合将应用程序设置存储在配置文件中(并且工作正常(。这对于给出的例子更有意义。但是这个问题纯粹与如何定义要由Aurelia DI解析的类的接口或特定实例有关。

> @estus提供的答案是正确的,我已将其标记为答案。虽然,我确实遇到了一些额外的问题来使其正常工作。为了指出这一点,我花时间在下面写了一个带有更多详细信息的答案,希望将来可以帮助其他人。

1.( 使用类,而不是接口 就像接受的答案状态一样,您不能使用接口
- 它必须是一个类。

2.(通过 aurelia.container 访问全局容器实例
文档没有提到如何获取容器的实例。但是你可以通过aurelia.container直接调用configure()操作中的默认/全局容器,如下所示:

aurelia.container.registerSingleton(RemoteServiceConfig, () => {
var config = new RemoteServiceConfig();
config.endpoint = 'http://foo.com/api/v23/',
config.apiKey = 'abc'
});

我犯了初始化 Container(( 的新实例的错误,并尝试以某种方式在 configure(( 操作中注入它。我不应该有:)

3.(将类拆分到不同的文件中 这看起来很愚蠢,但很重要:这些类不能位于同一个文件中
,否则您将收到以下错误:

键/值不能为 null 或未定义。您是否正在尝试注入/注册 DI 不存在的内容?

出于原始问题的目的,我在同一个 app.ts 文件中创建了所有类。这似乎根本行不通。

话虽如此,完整的应用程序现在看起来像这样并且可以工作:

主目录

import { Aurelia } from 'aurelia-framework'
import { RemoteServiceConfig } from './app';
export function configure(aurelia: Aurelia) {
aurelia.use
.standardConfiguration()
.feature('resources');
aurelia.container.registerSingleton(RemoteServiceConfig, () => {
var config = new RemoteServiceConfig();
config.endpoint = 'http://foo.com/api/v23/',
config.apiKey = 'abc'
});
aurelia.start().then(() => aurelia.setRoot());
}

应用程序

import { autoinject } from 'aurelia-dependency-injection';
// note: classes below should be 3 different files!
@autoinject
export class App {
constructor(private service: CustomerService) {
}
}
@autoinject
export class CustomerService {
constructor(private config: RemoteServiceConfig) {
}
}
export class RemoteServiceConfig {
public endpoint: string;
public apiKey?: string;
}

无论使用哪个 TypeScript 版本,接口在运行时都不存在。

为了同时用作接口和 DI 令牌,IRemoteServiceConfig应该是一个类:

export abstract class IRemoteServiceConfig { ... }