【问题标题】:Circular dependency caused by importing typescript type导入 typescript 类型引起的循环依赖
【发布时间】:2018-07-03 06:03:45
【问题描述】:

我正在对从服务器发送到我的 Angular 应用程序的打字稿中的数据进行建模。 Opportunity 有一个 forms 属性,其中包含一个 Form[] 对象数组。 Form 有一个parent 属性,其中可能包含一个Opportunity。为了解析类型,定义Opportunity的文件导入Form,定义Form的文件导入Opportunity。这会产生循环依赖警告。

我发现了几个处理循环依赖关系的先前 SO 问题(herehere),但在每种情况下,它们都在处理 javascript 代码中的循环依赖关系。这种情况下,循环依赖只针对typescript类型,编译后不存在。有没有办法在文件中包含一个类型,同时避免这种循环依赖问题?到目前为止,我还没有找到任何东西。

我能想到两个解决这个问题的办法:

  1. 在同一个文件中定义两个模型
  2. Opportunity 文件中重新创建Form 接口/在Form 文件中创建Opportunity 接口。

还有其他/更好的解决方案吗?谢谢!

更新 2

我似乎找到了an answer(由于某种原因,它在问题列表中的位置非常靠后)。这个答案提出了两种可能性

  1. 创建一个单独的定义文件(这似乎涉及重新创建OpportunityForm 类接口,因此不会比上面的选项#2 更好)。

  2. 使用导入,这是我已经在做的(并且导致循环依赖警告)。

有没有办法导入一个类的关联接口?

更新 3

需要明确的是,目前OpportunityForm 看起来像这样:

// opportunity.ts
import { Form } from '....../form'

export class Opportunity {
  public forms: Form[] = [];
}

// form.ts
import { Opportunity } from '....../opportunity'

export class Form {
  public parent: Opportunity;
}

【问题讨论】:

  • 您可以在form.ts 文件中声明一个类declare class Opportunity {},TypeScript 将假定该类是一个外部类并且在运行时可用。您可以跳过其中一堂课的导入。
  • @AkashKava 谢谢!!我可以接受这个答案,也许这是最好的解决方案。虽然它不是完美,因为以这种方式声明类会从我的IDE(VS Code)中删除各种自动完成选项。我假设是因为 IDE 不再对声明的类一无所知。为了夺回自动补全能力,唯一的办法是手动重新定义界面吗?

标签: angular typescript


【解决方案1】:

来自打字稿版本 3.8

import type 会帮助你。

https://www.typescriptlang.org/docs/handbook/release-notes/typescript-3-8.html

【讨论】:

  • 被低估的答案,但效果最好!
【解决方案2】:

另一种方法是在一个类中使用require 而不是import
看起来像:

let LoginPage = require("./loginpage").default;
return new LoginPage();

您可以在post最佳实践#5中找到它。

【讨论】:

    【解决方案3】:

    您可以通过依赖抽象来移除循环依赖,例如您的form 模块可以定义parent 必须确认的接口或抽象类。

    这意味着您的opportunity 模块将依赖于form 模块,但反之则不然。您可以将具体的Opportunity 注入到Form.parent 属性中,这是可以接受的。

    这也允许您定义一个FormParent(见下文),它是Opportunity 的子集,因为您可能不依赖Opportunity 中的所有内容

    由于 TypeScript 是结构化的,是否在 Opportunity 类上显式实现接口取决于您。

    // 机会.ts

    import { Form } from '....../form'
    
    export class Opportunity {
      public forms: Form[] = [];
    }
    

    // form.ts

    interface FormParent {
        forms: Form[];
    }
    
    export class Form {
      public parent: FormParent;
    }
    

    【讨论】:

    • 也是一个很好的答案!我的问题稍微简单化了。在Form 上,我实际上有public parent: FormParent;,其中type FormParent = Opportunity | ContactList;。我没有想到我可以将FormParent 变成其他类可以扩展的抽象类。我一定会牢记这个想法。但是,当从服务器拉出Form 时,JSON 可能包含用于构造父属性的 args。接受答案的一个优点是,在Form 构造函数中,我可以实例化new Opportunity(),因为已经声明了机会。
    【解决方案4】:

    您可以在 form.ts 文件中声明一个类 declare class Opportunity {},TypeScript 将假定该类是一个外部类并且将在运行时可用。您可以跳过其中一堂课的导入。

    这里唯一的痛苦是,您必须声明将要使用的方法,例如,

    declare class Opportunity {
         method1(): void;
         method2(): number;
    }
    

    这个类将作为简单的声明,不需要方法体。并且 VS intellisense 会正常工作。

    【讨论】:

      猜你喜欢
      • 2019-12-09
      • 1970-01-01
      • 2016-02-27
      • 2010-12-06
      • 2016-11-09
      • 2023-04-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多