我正在用tsyringe学习DI。我对DI的概念也完全陌生。
以下代码段有效,container.resolve(Foo)
正确地实例化了依赖项。
import "reflect-metadata";
import { injectable, container } from "tsyringe";
class Database {
get() {
return "got-stuff-from-database";
}
}
@injectable()
class Foo {
constructor(private database: Database) {}
checkDb() {
return this.database.get();
}
}
const fooInstance = container.resolve(Foo);
console.log(fooInstance.checkDb());
//=> got-stuff-from-database
这是可以理解的。但是下面的片段(大部分取自他们的自述(对我来说不起作用,我也不能理解,也不能理解为什么我们有了上面的injectable
装饰器就需要inject
。很抱歉,我在网上搜索了一下,发现每个人都在使用它,就像每个人都知道的一样。
interface Database {}
@injectable()
class Foo {
constructor(@inject("Database") private database?: Database) {}
checkDb() {
return 'stuff';
}
}
const fooInstance = container.resolve(Foo);
console.log(fooInstance.checkDb());
所以需要记住的主要一点是tsyringe是一个Typescript库。当Typescript被编译为Javascript时,接口基本上不再存在(就像您的示例中的Database
接口(,所以类中发生的DI魔法不能像往常一样完成。文档是这样解释的:
接口在运行时没有类型信息,因此我们需要用@inject(…(装饰它们,这样容器就知道如何解决他们
它仍然不适用于您的原因是,您只告诉DI框架,它必须查找在令牌"Database"
下注册的东西的实例,但实际上没有在那里注册任何东西。因此,要使其工作,您仍然需要告诉tsyringe"Database"
有一个类或实例与之关联,如下所示:
container.register("Database", {
useClass: SomeDatabaseImplementation
});
请注意,您仍然必须创建所述实现,因为您无法实例化接口。为了更深入地理解,我建议你看一下库的源代码,它很容易理解,让你更好地了解内部工作原理。