SystemJS 中的 TypeScript 继承和循环依赖

TypeScript inheritance and circular dependencies in SystemJS

我在一个非常大的项目中使用带有 --module system (SystemJS) 的 TypeScript。 SystemJS 支持循环依赖,并且大多数时候它工作正常。然而,当涉及到 TypeScript 继承时,事情就开始崩溃了。

例如,如果 class A 依赖于 class B,并且 class B class A 继承 ,那么如果 class A 首先加载:

  1. 它将暂停 class A's 解析并尝试加载 class B 依赖项
  2. class B 会认为其依赖项已解决,因为 class A 已被触及。
  3. class B's 继承将无法解析,因为 class A 仍未定义。

我在网上找到的大多数 "solutions" 与模块加载器的循环依赖关系是:

我觉得循环设计有合理的理由,并且将 类 组合成巨型文件并不总是可取的,所以请考虑这些变通方法与我提出的问题无关。

有没有解决实际问题的方法?

改变你的设计是最有利的解决方案。 class 不应依赖于其子class。如果您在工厂左右使用它们,那是一个单独的问题,应该放在单独的 class/function/module.

Are there any solutions to the actual problem?

正如你所说,只有在先加载模块A时才会出现这个问题。解决方案是防止这种情况发生,并编写一个额外的模块作为 A 及其所有子class的代理,同时以正确的顺序导入它们。

在这种情况下,我建议您通过创建一个单独的接口 I 来删除对 A -> B 的依赖。 AB都需要知道IB需要实现

在加载过程中,B 必须告诉 A 在哪里可以找到 I 的构造函数或工厂(由 B 实现)。这将为您留下这些依赖项:

A -> I
B -> I
B -> A

界面 I 可能如下所示:

interface I {
  bFoo(): void;
}

export default I;

Class A 可能看起来像这样:

import I from "./i";

class A {
  private static __ICtor : new() => I;
  public static setIConstructor(ctor: new() => I) {
    A.__ICtor = ctor;
  }

  private __atSomePoint() : I {
    return new A.__ICtor();
  }
}

export default A;

最后 class B:

import I from "./i";
import A from "./a";

class B extends A implements I {
  public bFoo() {}
}

A.setIConstructor(B);

恕我直言,这将解决您的循环依赖,即使现在为时已晚。

使用 Babel 转换插件可以解决这个问题:https://github.com/zertosh/babel-plugin-transform-inline-imports-commonjs

它所做的是将文件开始时的模块导入转换为内联,这实际上只需要 import/require 其他模块在使用之前。

在大多数情况下,这会自动解决问题,因为到任何 class-using 代码实际运行时,模块都已完成导出。


请注意,默认情况下,上面的插件适用于项目中的所有导入,将它们全部转换为内联需求。然而,一个更严重的问题是我找不到一种内置的方法来使其与相对路径 imports/requires.

一起工作

我在我的项目分支中修复了这两个问题:https://github.com/Venryx/babel-plugin-transform-inline-imports-commonjs

我对这些更改提出了拉取请求,但它正在等待审查 atm。