加载程序异常/装饰者的循环引用

时间:2019-04-14 11:22:00

标签: node.js typescript commonjs typeorm reflect-metadata

问题

我得到了循环加载程序异常。这可能是由编译器选项"emitDecoratorMetadata":true引起的。 我该如何解决?感谢您提供有用的重播!

简介

我已经准备了一个最小项目来重现该错误。请查看我的临时git存储库:git repo for bug presentation

我使用两个库(typeormjson2typescript),并且都使用装饰器。我在两个类属性的两个库中使用了多个装饰器。

复制步骤:

  1. 克隆git仓库。
  2. 通过命令npm i(npm 6.9.0)安装所有软件包。
  3. 通过Visual Studio Code打开根目录。
  4. 打开bugexample/test/test.spec.ts,进入调试视图并通过配置Mocha current file开始调试。

完成这些步骤后,您应该会看到异常输出。

/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".

属性banana获取类型Banana作为参数,由于未知原因,该类型为undefined。库json2typescript并非引起此问题的原因。


分析

现在,我想解决这个问题。 我从两个模型类开始,然后以测试结束。

首先,请看一下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();
}

在第24行中,类型Banana是传递的参数,但由于未知原因,它是当前测试的undefined

现在请看一下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();
}

第21和22行有问题。如果我将这些行注释掉,那么没有加载程序异常。

最后,请看看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;
  })
})

我要测试类型/类Banana是否未定义,但是测试会更早中断,因为如果传递的属性(在这种情况下,类型为{{1 }})是json2typescript

奇怪的行为是,如果我将类Banana分配给变量(在第6行删除注释),则定义了类型/类undefined


1 个答案:

答案 0 :(得分:1)

我知道我对此事有些迟了,但是我遇到了类似的问题并找到了这篇文章。深入研究后,我意识到json2typescript根本不是问题,而是循环依赖问题。

我发现这篇非常有用的文章可以帮助我解决项目中的问题:https://medium.com/visual-development/how-to-fix-nasty-circular-dependency-issues-once-and-for-all-in-javascript-typescript-a04c987cf0de

本质上,问题是:

  • ape.model.ts中,您要导入香蕉:import { Banana } from "./banana.model";
  • 您在banana.model.ts中导入猿:import { Ape } from "./ape.model";

这些模块是按顺序加载的,因此,当第一个模块被加载时(让其装成ape.model.ts),它将尝试导入香蕉->香蕉将被加载,试图导入猿->猿还没有完成加载因此它返回的是undefined。

我所链接的文章提出的解决方案建议您创建一个internal.ts文件来管理模块加载:

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

然后总是从内部加载,即在ape.model.ts中加载

import { Banana } from './internal';