Typescript 如何使对象工厂维护类型
我创建了以下对象工厂来实例化我所有接口的实现:Typescript 如何使对象工厂维护类型,typescript,design-patterns,factory,Typescript,Design Patterns,Factory,我创建了以下对象工厂来实例化我所有接口的实现: interface-SomeInterface{ get():字符串; } 类实现实现了一个接口{ 构造函数(){} 得到(){ 返回“Hey:D”; } } 类型可注射={ [键:字符串]:()=>未知; }; //deno lint忽略首选常量 让默认_实现:可注入={ SomeInterface:()=>新实现(), }; 让MOCK_实现:Injectable={}; 阶级工厂{ 静态getInstance(interfaceName:st
interface-SomeInterface{
get():字符串;
}
类实现实现了一个接口{
构造函数(){}
得到(){
返回“Hey:D”;
}
}
类型可注射={
[键:字符串]:()=>未知;
};
//deno lint忽略首选常量
让默认_实现:可注入={
SomeInterface:()=>新实现(),
};
让MOCK_实现:Injectable={};
阶级工厂{
静态getInstance(interfaceName:string,参数:unknown=[]){
if(模拟实现[interfaceName])
返回MOCK_实现[interfaceName]();
返回默认的_实现[interfaceName]();
}
静态mockWithInstance(interfaceName:string,mock:unknown){
MOCK_实现[interfaceName]=()=>MOCK;
}
}
导出常量ObjectFactory={
getInstance(名称:string):T{
将Factory.getInstance(name)返回为T;
},
mockWithInstance:Factory.mockWithInstance,
};
const impl=ObjectFactory.getInstance(“SomeInterface”);
如您所见,此工厂允许您实例化和模拟这些接口。主要的问题是,我必须使用接口和接口的名称调用此函数,以便在赋值中保留类型:
ObjectFactory.getInstance(“SomeInterface”)
我看到了,但我不喜欢使用Base
接口。此外,这种方法也不能保持这种类型
理想情况下,我希望使用我的方法,但不必使用接口,也就是说,只使用接口的名称
旁注:Injectable
的声明是一种使代码正常工作的技巧,理想情况下,我希望能够只使用实现名称,即:
let DEFAULT_实现={
SomeInterface:实现
}
由于您有一个关心支持的名称到类型映射的固定列表,因此这里的一般方法是根据表示此映射的对象类型T
来考虑,然后对于任何受支持的接口名称K extends keyof T
,您将处理以该名称返回属性的函数。。。即,类型为()=>T[K]
的函数。另一种说法是,我们将使用它来帮助您的工厂提供型号
对于T
,我们将只使用一个具体的类型,如{“SomeInterface”:SomeInterface;“Date”:Date}
,但是在接下来的过程中,如果T
是泛型的,编译器将更容易处理事情。下面是ObjectFactory
maker的一个可能的通用实现:
function makeFactory<T>(DEFAULT_IMPLEMENTATIONS: { [K in keyof T]: () => T[K] }) {
const MOCK_IMPLEMENTATIONS: { [K in keyof T]?: () => T[K] } = {};
return {
getInstance<K extends keyof T>(interfaceName: K) {
const compositeInjectable: typeof DEFAULT_IMPLEMENTATIONS = {
...DEFAULT_IMPLEMENTATIONS,
...MOCK_IMPLEMENTATIONS
};
return compositeInjectable[interfaceName]();
},
mockWithInstance<K extends keyof T>(interfaceName: K, mock: T[K]) {
MOCK_IMPLEMENTATIONS[interfaceName] = () => mock;
}
}
}
这一切都如我所想。我们使用所需的DEFAULT\u实现调用makeFactory
来创建ObjectFactory
。这里我已经注释了SomeInterface
属性返回类型为SomeInterface
的值(否则编译器将推断实现
,这可能比您希望的更具体)
然后我们可以看到,编译器允许我们使用正确的参数调用ObjectFactory.getInstance()
和ObjectFactory.mockWithInstance()
,并返回预期的类型,而且它在运行时也可以工作
编译时是否知道接口列表?或者随着时间的推移,你会添加新的吗?我希望这里的代码是这样的:这里唯一存在的问题是您正在询问的问题,一些行显示了预期与实际的行为。现在为了处理这个问题,我必须处理ConcreteImplementation
是什么,我在代码中没有看到用例。我已经编辑了示例,以防您需要更多信息,我在大学项目中尝试使用干净的体系结构创建解析器,在此项目中,我简化了用例:。您可以使用断言函数“动态”将接口添加到列表中,但这比仅使用固定列表更复杂、更脆弱。这些编辑会产生问题,因为它们有语法错误(大引号无效)和其他问题(new Implementation()
不是有效的()=>未知的,没有名为getInstance()
)的函数)请考虑将示例代码放入IDE并在发布之前测试它的行为。我现在必须退出,但我的问题仍然是:您是否需要通过<代码> MoCKION StIN()添加接口?
,还是只使用现有接口的固定列表?前者可以使用断言函数,但后者更简单。很抱歉,它现在已经固定。是的,我使用现有接口的固定列表。我导入它们并像SomeInterface一样添加它们。首先,非常感谢您令人难以置信的回答。我只是想知道如果有可能摆脱SomeInterface:()=>new SomeImplementation()hack。我的意思是,将可用接口声明为SomeInterface:SomeImplementation,并在makeFactory函数中创建它们。您就是编写SomeInterface:()=>new Implementation()的人
在示例代码中,因此我不确定这到底是一个什么样的黑客行为?您是否在寻找类似于maybe的东西?如果不是,请详细说明,但请记住,这可能超出了所问问题的范围,无法在此处进一步讨论。这是一个黑客行为,因为我必须这样做才能使我的旧解决方案工作:/。我的意思是:s只是使用{SomeInterface:SomeImplementation}作为makeFactory函数的参数。很抱歉,我应该说这是问题中的一个漏洞。我已经在问题中添加了一个编辑,但这是我的错,所以请随意忽略我的请求,您已经帮了我很多。
const ObjectFactory = makeFactory({
SomeInterface: (): SomeInterface => new Implementation(),
Date: () => new Date()
});
console.log(ObjectFactory.getInstance("SomeInterface").get().toUpperCase()); // HEY :D
ObjectFactory.mockWithInstance("SomeInterface", { get: () => "howdy" });
console.log(ObjectFactory.getInstance("SomeInterface").get().toUpperCase()); // HOWDY
console.log(ObjectFactory.getInstance("Date").getFullYear()); // 2020