【问题标题】:Complex TypeScript circular dependency problem复杂的 TypeScript 循环依赖问题
【发布时间】:2019-11-29 18:12:05
【问题描述】:

我的 Angular 应用的数据模型中有一个相当复杂的依赖结构。

在抽象形式中,它看起来像这样(A -> B 表示“A 导入 B”):

从这个结构中我得到了很多循环依赖,我很难解决这个问题。我已经尝试应用提到的解决方案here:我尝试使用internal.ts 文件并导出该文件中的所有类。导入任何类时,我再次从./internal.ts 文件中导入它们。

不过,问题仍然存在。唯一改变的是错误消息的形式:

来自

Circular dependency detected: C.ts -> D.ts -> E.ts -> C.ts

Circular dependency detected: C.ts -> internal.ts -> C.ts
Circular dependency detected: D.ts -> internal.ts -> D.ts
Circular dependency detected: E.ts -> internal.ts -> E.ts

有没有其他方法可以解决这样的问题?

【问题讨论】:

    标签: angular typescript circular-dependency


    【解决方案1】:

    linked article 中提出的解决方案并没有消除循环依赖——它只是通过仔细控制加载顺序来避免它们可能造成的任何灾难性影响。引用:

    这解决了我们的问题的原因是:我们现在可以完全控制 超过模块加载顺序。无论进口订单是什么 internal.js 是,将是我们的模块加载顺序。

    循环依赖只会有问题,因此模块加载顺序只有在你有模块在加载时立即评估它们的导入时才真正重要 - 即导入的值用于主体模块:

    // Foo.js
    import { Bar } from "./Bar"
    
    export class Foo {
      getBarClass() {
        return Bar;
      }
    }
    
    
    // Bar.js
    import { Foo } from "./Foo"
    
    console.log(Foo.name);           // Foo eval'ed on load :(
    export const fooClass = Foo;     // Foo eval'ed on load :(
    
    export class Bar extends Foo {   // Foo eval'ed on load :(
      static fooClass = Foo;         // Foo eval'ed on load :(
      fooClass = Foo;                // Eval'ed only on new Bar()
    
      static getFooClass() {        
        return Foo;                  // Eval'ed only on Bar.getFooClass()
      }
    
      getFooClass() {                
        return Foo;                  // Eval'ed only on someBar.getFooClass()
      }
    }
    

    在此示例中,Foo.js 在加载时不会访问 Bar,仅在稍后调用 getBarClass 时才访问。另一方面,Bar.js 在加载时会多次访问导入的Foo。因此,Bar.js 必须先加载。

    一旦您不再在加载时立即访问导入,循环依赖就不再是问题:

    // execute in next tick
    setImmediate(() => console.log(Foo.name));
    
    // wrap in function
    export const getFooClass = () => Foo;
    
    // wrap in function
    export const getBarClass = () => {
      return class Bar extends Foo {
        static fooClass = Foo;
        fooClass = Foo;
      };
    };
    

    当然,这些延迟评估的解决方案看起来相当难看,所以最后你可能想要使用仔细协调的加载顺序。

    【讨论】:

    • 我只是不喜欢我的构建中的警告。如果我玩弄加载顺序,我可以让这些警告消失吗?或者,是否总是有一个无法解决的问题?
    • @DanielKaplan 这取决于您的代码的结构。我还没有处理没有它们的非平凡的 Angular 或 Node.js 项目。我通常只是关闭警告...
    猜你喜欢
    • 1970-01-01
    • 2015-01-25
    • 1970-01-01
    • 2019-12-09
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多