0

问题

我得到一个循环加载程序异常。这可能是编译器选项造成的"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是否未定义,但测试会提前中断,因为如果传递的属性(在本例中为 type )库json2typescript会引发异常。Bananaundefined

奇怪的行为是,如果我将类分配Ape给一个变量(删除第 6 行的注释),那么类型/类Banana就被定义了。


4

1 回答 1

1

我知道我对此有点晚了,但我遇到了类似的问题并找到了这篇文章。在挖掘之后,我意识到这根本不是 json2typescript 的问题,而是循环依赖问题。

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

本质上,问题是:

  • ape.model.ts你进口香蕉:import { Banana } from "./banana.model";
  • banana.model.ts你进口猿:import { Ape } from "./ape.model";

这些模块是串行加载的,所以当第一个模块被加载时(假设它的ape.model.ts)它尝试导入香蕉-> 香蕉被加载,它试图导入猿-> 猿还没有完成加载,所以它返回未定义。

我链接到的文章建议您创建一个internal.ts用于管理模块加载的文件:

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

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

import { Banana } from './internal';
于 2020-03-11T01:48:24.360 回答