Typescript 如何以可用的方式重新导出导入的模块,该模块中包含接口?
我有一个包含大量模块的文件。我想将这些模块分离成不同的文件,并从原始文件中公开它们。这是因为原始文件>800 loc,并且变得非常难以管理 因此,我创建了一个文件,其中包含一个具有函数和接口的模块:Typescript 如何以可用的方式重新导出导入的模块,该模块中包含接口?,typescript,Typescript,我有一个包含大量模块的文件。我想将这些模块分离成不同的文件,并从原始文件中公开它们。这是因为原始文件>800 loc,并且变得非常难以管理 因此,我创建了一个文件,其中包含一个具有函数和接口的模块: 导出模块子节1{ 导出接口{ id:字符串; } 导出函数DoInterfaceStuff(obj:any){ return={id:obj} } } 我有 从“/Subsection1”导入{Subsection1作为Subsection1Base}”; 导出模块管理器{ 导出类型Subsec
导出模块子节1{
导出接口{
id:字符串;
}
导出函数DoInterfaceStuff(obj:any){
return={id:obj}
}
}
我有
从“/Subsection1”导入{Subsection1作为Subsection1Base}”;
导出模块管理器{
导出类型Subsection1=Subsection1Base和(typeof Subsection1Base);
导出var Subsection1=Subsection1Base;
var ObjByID=新映射();
导出函数点(源){
ObjByID.set(source.id,Subsection1.DoInterfaceStuff(source.origin));
}
}
注意
新名称和变量必须在当前类外部可访问,因为我实际上是在延迟加载Subsection1Base(主要是为了避免循环依赖)。Prelude
该问题更改了示例代码,但他们最初导出了一个模块
和接口
,并尝试在只有接口
有效的上下文中引用模块
。虽然在不同语言结构的两个不同声明之间共享一个名称并不一定是错误的,但它确实掩盖了他们所经历的真实问题(见下面的原始答案)
原始答案
如果我们清理了类型的命名,我们可以很快找出这里的错误
在TriggerEvent中,我们将接口Trigger
重命名为ITrigger
:
export interface ITrigger {
// ..
}
export module Trigger {
//...
export function Serialise(restoredEvent: ITrigger) {
//...
}
}
现在,在ActionManager
中,我们可以看到哪里出了问题:
import { Trigger as TriggerBase } from "./TriggerEvent";
export module ActionManager {
type Trigger = TriggerBase & (typeof Trigger);
// ^^^^^^^^^^^
// ERROR - Cannot use namespace 'TriggerBase' as a type.
var Trigger = TriggerBase;
var EventsByID = new Map<UUID, Trigger>();
var PrepreparedInputs = new Map<UUID, Trigger.Serialised>();
// ^^^^^^^
// ERROR - 'Trigger' only refers to a type, but is being used as a namespace here.
}
并且,正如您使用TriggerEvent
所做的那样,导出要在模块外部使用的类型/变量:
// The interface was renamed to ITrigger in TriggerEvent.
import { Trigger as TriggerBase, ITrigger } from "./TriggerEvent";
export module ActionManager {
export var Trigger = TriggerBase;
export var EventsByID = new Map<UUID, ITrigger>();
export var PrepreparedInputs = new Map<UUID, TriggerBase.Serialised>();
}
//该接口在TriggerEvent中重命名为ITrigger。
从“/TriggerEvent”导入{Trigger as TriggerBase,ITrigger};
导出模块ActionManager{
导出var触发器=TriggerBase;
导出var EventsByID=newmap();
export var preprepreparedinputs=新映射();
}
@Connor Low的回答通过突出显示正确的错误为我指明了正确的方向,但这是问题的实际解决方案
从其他文件导入的模块可以使用import-export-Name=Value
语法重新导出
因此,重写示例代码,解决方案是:
从“/Subsection1”导入{Subsection1作为Subsection1Base};
导出模块管理器{
导出-导入子部分1=子部分1基础;
var ObjByID=新映射();
导出函数点(源){
ObjByID.set(source.id,Subsection1.DoInterfaceStuff(source.origin));
}
}
一切都很好 为什么同时调用接口和模块(名称空间)触发器
?您可以调用接口ITrigger
。我在typescript中经常使用这种模式,主要是为了从类中获取静态方法和成员来清理代码。这一次,它是一个接口,这一事实并不常见,我后来发现,它实际上可能与真正的问题无关。我相信,如果模块被重新导出,那么模块中定义的任何接口都会出现问题(它会丢失内部接口的键入信息)。看起来typescript中已经有一个功能要求,就是这个功能:Offtopic rant:将静态功能拆分为一个名为与类本身相同的模块类不会让每个人都发疯。你就是不喜欢。这个模式与C++如何将定义拆分成一个单独的文件非常相似,我没有看到任何人抱怨。所有的东西都在同一个文件中,F12在每个编辑器中仍然能找到正确的函数,它只是使文件内导航变得更容易。我不知道C++定义分割(这是不是像C?部分类?),但是<代码>模块<代码>是一个完全不同的类型,而不是<代码>接口<代码>。这就是导致询问者问题的原因(他们认为他们包含了一个模块,但实际上是接口)。我相信其中的细微差别比我们任何一方透露的都要多。没有比这更重要的了。在C++中,所有的类定义(变量签名、方法签名、公共和受保护的修饰符)必须在.h文件中指定,并且内容在.cpp文件中。这也是C.的情况,我的评论是回复你说它会让每个人都很疯狂,很明显你对很多不同的编程语言没有太多的经验,所以我建议你在某个时候给C++尝试一下。这是一门很棒的语言。相关:编译错误只是编译器中的一个bug,合并接口在它们的文档中,所以它是受支持的。我也是最初的提问者。很好,我更新了我的答案。我仍然认为最好区分(通过唯一命名)模块和接口,因为它们在typescript中是完全不同的东西,但我的陈述太宽泛了。
// The interface was renamed to ITrigger in TriggerEvent.
import { Trigger as TriggerBase, ITrigger } from "./TriggerEvent";
export module ActionManager {
export var Trigger = TriggerBase;
export var EventsByID = new Map<UUID, ITrigger>();
export var PrepreparedInputs = new Map<UUID, TriggerBase.Serialised>();
}