网站搜索

ECMAScript 6 - TypeScript 继承与 SystemJS 中的循环依赖


我在一个非常大的项目中使用 TypeScript,并使用 --module system(SystemJS)。SystemJS 支持循环依赖,大多数时候它都能正常工作。然而,当涉及到 TypeScript 的继承时,情况开始出现问题。

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

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

我在网上找到的大多数关于使用模块加载器处理循环依赖的“解决方案”要么是:

  • 更改你的设计/将类合并到一个模块中
  • CommonJS 和非 TypeScript 特定的解决方法

我觉得对循环设计有合理的理由,而且将类合并到巨大的文件中并不总是理想的,所以请考虑这些解决方法与我所提出的问题无关。

对实际问题有任何解决方案吗?

答案#1

改变你的设计是最可取的解决方案。一个类不应依赖于它的子类。如果你在工厂或其他地方使用它们,那是一个单独的问题,应该放在一个单独的类/函数/模块中。

对实际问题有任何解决方案吗?

正如你所说,问题仅在模块A首先被加载时发生。解决办法是防止这种情况,并编写一个额外的模块,在以正确顺序导入它们时充当A及其所有子类的代理。

答案#2

在这种情况下,我建议你通过创建一个独立的接口 I 来移除 A -> B 的依赖。A 和 B 都需要知道 I,并且 B 需要实现它。

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

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

接口 I 可能看起来像这样:

interface I {
  bFoo(): void;
}

export default I;

类 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);

依我看,这可以解决你的循环依赖问题,即使现在可能已经太晚了。

相关文章