Javascript 带有typescript接口的Aurelia DI
我已经阅读了Aurelia DI的文档,并查看了源代码,希望与大家分享我试图实现的目标,这样,如果我遗漏了一些明显的东西,我就可以被击倒。我已经看过了Aurelia TS的样本,但我看不出它将如何工作,并且缺少文档 我想要的是: dataProvider.js(数据提供程序接口) itemDisplayer1.js(一个类,它将使用实现接口的注入类) itemDisplayer2.js(另一个类将使用实现接口的注入类) GoodDataProvider.jsJavascript 带有typescript接口的Aurelia DI,javascript,dependency-injection,aurelia,Javascript,Dependency Injection,Aurelia,我已经阅读了Aurelia DI的文档,并查看了源代码,希望与大家分享我试图实现的目标,这样,如果我遗漏了一些明显的东西,我就可以被击倒。我已经看过了Aurelia TS的样本,但我看不出它将如何工作,并且缺少文档 我想要的是: dataProvider.js(数据提供程序接口) itemDisplayer1.js(一个类,它将使用实现接口的注入类) itemDisplayer2.js(另一个类将使用实现接口的注入类) GoodDataProvider.js import {DataProvid
import {DataProvider} from "./dataProvider";
export class GoodDataProvider implements DataProvider {
data = 1;
getData() {
return this.data;
}
}
import {DataProvider} from "./dataProvider";
export class BetterDataProvider implements DataProvider {
data = 2;
getData() {
return this.data;
}
}
BetterDataProvider.js
import {DataProvider} from "./dataProvider";
export class GoodDataProvider implements DataProvider {
data = 1;
getData() {
return this.data;
}
}
import {DataProvider} from "./dataProvider";
export class BetterDataProvider implements DataProvider {
data = 2;
getData() {
return this.data;
}
}
然后在某个地方(?)我想配置itemDisplayer1应该提供GoodDataProvider的实例,itemDisplayer2应该提供BetterDataProvider(1)的实例
然后是DI上下文的问题。我不知道如何使用container.createChild()。我找不到太多关于它的信息。它创建一个子容器,并在需要时将委托回父容器,但是如果我创建2个子容器并向每个子容器注册2个提供者中的一个,itemDisplayer类如何知道使用哪一个(而不更改其定义并注入父容器等)
注意:生命周期管理信息不存在于依赖项的使用者或提供者中(这通常在Aurelia DI示例中完成,似乎有点做作)。我希望当消费者和提供者与上面的点(1)相关联时,能够定义这一点
总之,这可能吗?这是不是在不久的将来可能发生的事情?我是否应该尝试用满足我需求的定制容器替换Aurelia DI
(我尝试这样做的原因是,为了评估js框架,这些框架需要展示一个成熟的DI系统,将生命周期管理/AOP等功能作为标准之一)来自@eisenbergeffect:DI将在编写基准后进行一些内部检修 但与此相关的是,它不能与接口一起工作,因为TypeScript会在运行时编译这些接口 当您在DI容器中注册不同的类型时,您必须提供唯一的键,然后在@Inject(xxx)语句中指定适当的唯一键。钥匙可以是你喜欢的任何东西。通常人们使用类型本身作为唯一键(这会引起一些混淆),但您可以使用字符串、数字或其他任何您喜欢的东西
单元测试也提供了信息:正如Mike所说,Aurelia还不支持这种依赖解析特性。接口被编译掉,因此不能用作键(例如,
container.registerInstance(ISomething,newconcretesomething());
然而,有一个小技巧可以让你看起来像是在使用接口本身作为键
foo.ts:
export interface IFoo {
// interface
}
export const IFoo = Symbol();
bar.ts:
import {IFoo} from "./foo.ts";
export class Bar implements IFoo {
// implementation
}
main.ts:
import {IFoo} from "./foo.ts";
import {Bar} from "./bar.ts";
...
container.registerInstance(IFoo, new Bar());
...
import { IFoo } from "./ifoo.ts";
import { Bar } from "./bar.ts";
...
container.registerInstance(IFoo, new Bar());
...
这可以很好地编译,并且编译器知道何时根据使用它的上下文使用正确的重复类型。因此,正如其他人所说,TS总是编译接口,目前没有办法使用纯接口。然而,TS的一个有趣且常被忽略的特性是,它允许使用
类代码>作为一个接口,这允许绕过当前限制
export abstract class DataProvider {
getData(): number;
}
@singleton(DataProvider) // register with an alternative key
export class MyAwesomeDataProvider implements DataProvider {
}
@autoinject
export class DataConsumer {
constructor(dataProvider: DataProvider) {
}
}
在上面的代码中,我们声明了一个抽象类DataProvider
,它将确保它不会被TS编译掉。然后,我们使用DataProvider
的另一个键注册MyAwesomeDataProvider
,每次DataProvider时,它将返回MyAwesomeDataProvider
的一个实例已请求代码>
对于子容器,您应该执行container.createChild()
返回容器的新实例,只要从该子容器触发解析,您就应该得到正确的实例。唯一的问题是使用具有两个冲突键的装饰器。基本上,元数据存在于类本身,因此您不能让两个实例在数据提供程序下注册e> ,这肯定会(尽管我自己没有试过)引起问题,唯一的办法就是使用显式注册
export abstract class DataProvider {
getData(): number;
}
export class MyAwesomeDataProvider implements DataProvider {
}
export class MyMoreAwesomeDataProvider implements DataProvider {
}
child1 = container.createChild();
child1.registerSingleton(DataProvider, MyAwesomeDataProvider);
child2 = container.createChild();
child2.registerSingleton(DataProvider, MyMoreAwesomeDataProvider);
@autoinject
export class DataConsumer {
constructor(dataProvider: DataProvider) {
}
}
child1.get(DataConsumer); // injects MyAwesomeDataProvider
child2.get(DataConsumer); // injects MyMoreAwesomeDataProvider
喜欢Frank Gambino的想法,并找到了一种方法使其既能与@inject
一起工作,又能与@autoinject
一起工作。诀窍是使用自定义接口(因为接口是在TypeScript中保留的,我称之为@I)
装饰部件:
myClass.ts
import { autoinject } from 'aurelia-framework';
import { i } from './i.ts';
import { IFoo } from "./ifoo.ts";
@autoinject
export class MyClass {
constructor(@i(IFoo) foo: IFoo) {
foo.doSomething();
}
}
i、 ts:
其余部分与Frank Gambino的答案完全相同,但我添加它是为了完整性
…
ifoo.ts:
export interface IFoo {
doSomething(): void;
}
export const IFoo = Symbol("IFoo"); // naming the symbol isn't mandatory, but it's easier to debug if something goes wrong
一些学生:
import { IFoo } from "./ifoo.ts";
export class Bar implements IFoo {
doSomething(): void {
console.log('it works!');
}
}
main.ts:
import {IFoo} from "./foo.ts";
import {Bar} from "./bar.ts";
...
container.registerInstance(IFoo, new Bar());
...
import { IFoo } from "./ifoo.ts";
import { Bar } from "./bar.ts";
...
container.registerInstance(IFoo, new Bar());
...
它实际上可以与其他DI容器一起工作。要使它与Angular2一起工作(尽管你为什么要这样做?Aurelia更棒:),你只需要将i.ts文件中的interfaceSymbol
的类型更改为any
,而不是Symobl(“IFoo”)
writenewinjectiontoken(“IFoo”)
(InjectionToken类是一个有角度的东西,遗憾的是,它们不支持符号作为注入令牌,至少目前是这样)。我有一种不同的方法来解决这个问题,这对我来说很有效
参加以下课程:
export class Foo implements Bar {
}
我将此更改为以下内容:
import { Container } from 'aurelia-framework';
class Foo implements Bar {
}
export var foo = Container.instance.get(Foo) as Bar;
现在,我只需执行以下操作即可获得该类的类型化单例实例:
import { foo } from 'foo';
来自gitter频道的评论:但是在一个相关的注释中,它不能与接口一起工作,因为TypeScript会在运行时编译这些接口。谢谢你回复我。很高兴了解大修-知道什么时候(大致)会这样吗?我应该知道TS接口b