简体   繁体   English

加载器异常/装饰器的循环引用

[英]loader exception / circular reference by decorators

Question

I get a circular loader exception.我得到一个循环加载器异常。 This is may caused by the compiler option "emitDecoratorMetadata":true .这可能是由编译器选项"emitDecoratorMetadata":true How can I fix it?我该如何解决? Thanks for helpful replays!感谢有用的重播!

Introduction介绍

I have prepared a minimal project for reproducing the error.我准备了一个最小的项目来重现错误。 Please take a look at my temporary git repository: git repo for bug presentation请查看我的临时 git 存储库:用于错误演示的 git repo

I use two libraries ( typeorm and json2typescript ) and both operate with decorators.我使用两个库( typeormjson2typescript )并且都使用装饰器进行操作。 I use multiple decorators from both libraries on some class properties.我在某些类属性上使用了两个库中的多个装饰器。

Steps for reproducing:再现步骤:

  1. Clone the git repo.克隆 git 仓库。
  2. Install all packages by the command npm i (npm 6.9.0).通过命令npm i (npm 6.9.0) 安装所有软件包。
  3. Open the root directory by Visual Studio Code .通过Visual Studio Code打开根目录。
  4. Open bugexample/test/test.spec.ts , go to the debug view and start debugging by the config Mocha current file .打开bugexample/test/test.spec.ts ,进入调试视图,通过配置Mocha current file开始调试。

After these steps you should see an exception output.在这些步骤之后,您应该会看到异常输出。

/bugexample/node_modules/reflect-metadata/Reflect.js:553
                var decorated = decorator(target, propertyKey, descriptor);
                                ^
Error: Fatal error in JsonConvert. It is not allowed to explicitly pass "undefined" as second parameter in the @JsonProperty decorator.

        Class property: 
                banana

Use "Any" to allow any type. You can import this class from "json2typescript".

The property banana gets the type Banana as parameter and this type is undefined for unknown reasons.属性banana获取类型Banana作为参数,并且由于未知原因该类型undefined The library json2typescript is not the cause of this problem.json2typescript不是这个问题的原因。


Analysis分析

Now I want to breakdown the issue.现在我想分解这个问题。 I begin with the two model classes and end with the test.我从两个模型类开始,以测试结束。

At first, please take a look at bug_presentation/src/persistence/models/ape.model.ts .首先,请查看bug_presentation/src/persistence/models/ape.model.ts

import { JsonObject, JsonProperty } from "json2typescript";
import { Column, Entity, OneToOne, PrimaryGeneratedColumn } from "typeorm";

import { Banana } from "./banana.model";

/**
 * This is an entity class.
 * 
 * @author Tim Lehmann <l_@freenet.de>
 */
@JsonObject("Ape")
@Entity()
export class Ape {

  @PrimaryGeneratedColumn()
  readonly id: number

  @JsonProperty('0')
  @Column()
  readonly name: string = null

  // the associated table holds the foreign keys

  @JsonProperty('1', Banana)
  @OneToOne(type => Banana, banana => banana.possessionOf, { cascade: true })
  readonly banana = new Banana();
}

In line 24 the type Banana is the passed parameter but for unknown reasons it's undefined for the current test at this time.在第 24 行中,类型Banana是传递的参数,但由于未知原因,当前测试尚未undefined它。

Now take a look at bug_presentation/src/persistence/models/banana.model.ts , please.现在请看一下bug_presentation/src/persistence/models/banana.model.ts

import { JsonObject, JsonProperty } from "json2typescript";
import { Column, Entity, JoinColumn, OneToOne, PrimaryGeneratedColumn } from "typeorm";

import { Ape } from "./ape.model";

/**
 * @author Tim Lehmann <l_@freenet.de>
 */
@JsonObject("Banana")
@Entity()
export class Banana {

  @PrimaryGeneratedColumn()
  private readonly id: number

  @JsonProperty('0')
  @Column()
  readonly weight: string = null

  @OneToOne(type => Ape, possessionOf => possessionOf.banana)
  @JoinColumn({ name: "possessionOf" })
  readonly possessionOf: Ape = new Ape();
}

Line 21 and 22 are problematic.第 21 和 22 行有问题。 If I comment these lines out then there is no loader exception.如果我将这些行注释掉,则没有加载程序异常。

Please take a look at bug_presentation/test/test.spec.ts , lastly.最后请看一下bug_presentation/test/test.spec.ts

import { expect } from "chai";

import { Ape } from "../src/persistence/models/ape.model";
import { Banana } from "../src/persistence/models/banana.model";

// const classApe = Ape;
const classBanana = Banana;

describe("check if class type exist", () => {

  it('check class Ape is defined', () => {
        // expect(classApe).exist;
  })

  it('check class Banana is defined', () => {
    expect(classBanana).exist;
  })
})

I want to test that the type/class Banana isn't undefined, but the test breaks earlier because the library json2typescript throws an exception if the passed property (in this case type Banana ) is undefined .我想测试类型/类Banana是否未定义,但测试较早中断,因为如果传递的属性(在本例中为类型Banana )为undefined ,库json2typescript会引发异常。

The strange behavior is that if I assign the class Ape to a variable (remove the comment at line 6) then the type/class Banana is defined.奇怪的行为是,如果我将类Ape分配给一个变量(删除第 6 行的注释),则定义了类型/类Banana


I know I'm a bit late on this one but I ran into a similar issue and found this post.我知道我在这个问题上有点晚了,但我遇到了类似的问题并找到了这篇文章。 After digging around I realized it wasn't a problem with json2typescript at all, rather a circular dependency issue.在挖掘之后,我意识到这根本不是 json2typescript 的问题,而是循环依赖问题。

I found this pretty useful article which helped me fix the issue in my project: https://medium.com/visual-development/how-to-fix-nasty-circular-dependency-issues-once-and-for-all-in-javascript-typescript-a04c987cf0de我发现这篇非常有用的文章帮助我解决了项目中的问题: https : //medium.com/visual-development/how-to-fix-nasty-circular-dependency-issues-once-and-for-all- in-javascript-typescript-a04c987cf0de

Essentially, the problem is:本质上,问题是:

  • In ape.model.ts you import banana: import { Banana } from "./banana.model";ape.model.ts你导入香蕉: import { Banana } from "./banana.model";
  • In banana.model.ts you import ape: import { Ape } from "./ape.model";banana.model.ts你导入ape: import { Ape } from "./ape.model";

These modules are loaded in serially, so when the first gets loaded (lets pretend its ape.model.ts ) it tries to import banana -> Banana gets loaded which tries to import ape -> ape hasn't finished being loaded so it returns undefined.这些模块是串行加载的,所以当第一个被加载时(让我们假设它的ape.model.ts )它尝试导入香蕉 -> 香蕉被加载它试图导入 ape -> ape 尚未完成加载所以它返回不明确的。

The solution the article I linked to proposes you create a internal.ts file for managing module loading:我链接到的文章的解决方案建议您创建一个internal.ts文件来管理模块加载:

export * from './ape.model';
export * from './banana.model';

then always load from internal, ie in ape.model.ts :然后总是从内部加载,即在ape.model.ts

import { Banana } from './internal';

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM