定义全局 TypeScript 配置(接口),用于 Aurelia 依赖注入
Define global TypeScript config (interface), for use with Aurelia dependency injection
在 Aurelia 中,我有几个 classes 依赖于相同的配置。使用 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
}
在构造函数中注入配置非常适合测试,不需要我阅读每个 class 中的配置和设置。
这些服务依赖于相同的配置,我 想在我的应用程序启动期间定义一次 - 。
通读 Aurelia docs on dependency injection,我发现有几种方法可用于此目的,例如 registerInstance()
、registerResolver()
和 registerSingleton()
。文档确实缺少关于 how 和 where 的一些上下文来定义它。
我在启动例程的 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 启动服务,它就会自动获取我的(硬编码的) ) 配置?
注意this SO question中提到"it can’t work with interfaces because TypeScript compiles those away at runtime."。这个问题也有 2 年历史了,在 Aurelia 和 TypeScript 中都发生了很多变化。不管情况是否仍然如此,同样的问题也适用于 class 的实例而不是接口。
另请注意,我知道 aurelia-configuration 等库似乎适合将应用程序设置存储在配置文件中(并且工作正常)。这对于给出的示例更有意义。但是这个问题纯粹与我如何定义要由 Aurelia DI 解析的 class 的接口或特定实例有关。
无论使用哪个 TypeScript 版本,接口在运行时都不存在。
为了同时用作接口和 DI 令牌,IRemoteServiceConfig
应该是 class:
export abstract class IRemoteServiceConfig { ... }
@estus提供的答案是正确的,我已将其标记为答案。虽然,我确实遇到了一些额外的问题来让它正常工作。为了指出这一点,我花时间在下面写了一个包含更多详细信息的答案,希望它能对以后的其他人有所帮助。
1.) 使用 class,而不是接口
与接受的答案状态一样,您不能使用接口 - 它必须是 class.
2.) 通过aurelia.container
访问全局容器实例
文档没有提到如何获取容器的实例。但是你可以通过aurelia.container
在configure()
操作中直接调用default/global容器,像这样:
aurelia.container.registerSingleton(RemoteServiceConfig, () => {
var config = new RemoteServiceConfig();
config.endpoint = 'http://foo.com/api/v23/',
config.apiKey = 'abc'
});
我在初始化 Container() 的新实例时出错,还试图以某种方式将其注入到 configure() 操作中。我不应该 :)
3.) 将您的 class 拆分到不同的文件中
这看起来很愚蠢但很重要:classes 不能在同一个文件中,否则你会得到以下错误:
key/value cannot be null or undefined. Are you trying to inject/register something that doesn't exist with DI?
出于原始问题的目的,我在同一个 app.ts 文件中创建了所有 classes。这似乎根本行不通。
综上所述,完整的应用程序现在看起来像这样并且可以运行:
main.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());
}
app.ts
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;
}
在 Aurelia 中,我有几个 classes 依赖于相同的配置。使用 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
}
在构造函数中注入配置非常适合测试,不需要我阅读每个 class 中的配置和设置。
这些服务依赖于相同的配置,我 想在我的应用程序启动期间定义一次 - 。
通读 Aurelia docs on dependency injection,我发现有几种方法可用于此目的,例如 registerInstance()
、registerResolver()
和 registerSingleton()
。文档确实缺少关于 how 和 where 的一些上下文来定义它。
我在启动例程的 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 启动服务,它就会自动获取我的(硬编码的) ) 配置?
注意this SO question中提到"it can’t work with interfaces because TypeScript compiles those away at runtime."。这个问题也有 2 年历史了,在 Aurelia 和 TypeScript 中都发生了很多变化。不管情况是否仍然如此,同样的问题也适用于 class 的实例而不是接口。
另请注意,我知道 aurelia-configuration 等库似乎适合将应用程序设置存储在配置文件中(并且工作正常)。这对于给出的示例更有意义。但是这个问题纯粹与我如何定义要由 Aurelia DI 解析的 class 的接口或特定实例有关。
无论使用哪个 TypeScript 版本,接口在运行时都不存在。
为了同时用作接口和 DI 令牌,IRemoteServiceConfig
应该是 class:
export abstract class IRemoteServiceConfig { ... }
@estus提供的答案是正确的,我已将其标记为答案。虽然,我确实遇到了一些额外的问题来让它正常工作。为了指出这一点,我花时间在下面写了一个包含更多详细信息的答案,希望它能对以后的其他人有所帮助。
1.) 使用 class,而不是接口
与接受的答案状态一样,您不能使用接口 - 它必须是 class.
2.) 通过aurelia.container
访问全局容器实例
文档没有提到如何获取容器的实例。但是你可以通过aurelia.container
在configure()
操作中直接调用default/global容器,像这样:
aurelia.container.registerSingleton(RemoteServiceConfig, () => {
var config = new RemoteServiceConfig();
config.endpoint = 'http://foo.com/api/v23/',
config.apiKey = 'abc'
});
我在初始化 Container() 的新实例时出错,还试图以某种方式将其注入到 configure() 操作中。我不应该 :)
3.) 将您的 class 拆分到不同的文件中
这看起来很愚蠢但很重要:classes 不能在同一个文件中,否则你会得到以下错误:
key/value cannot be null or undefined. Are you trying to inject/register something that doesn't exist with DI?
出于原始问题的目的,我在同一个 app.ts 文件中创建了所有 classes。这似乎根本行不通。
综上所述,完整的应用程序现在看起来像这样并且可以运行:
main.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());
}
app.ts
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;
}