loader exception / may be a circular reference
Kcorab opened this issue · comments
You can find the following error description on StackOverflow.
Question
I get a circular loader exception. This is may caused by the compiler option "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
I use two libraries (typeorm
and json2typescript
) and both operate with decorators. I use multiple decorators from both libraries on some class properties.
Steps for reproducing:
- Clone the git repo.
- Install all packages by the command
npm i
(npm 6.9.0). - Open the root directory by
Visual Studio Code
. - Open
bugexample/test/test.spec.ts
, go to the debug view and start debugging by the configMocha 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. The library json2typescript
is not the cause of this problem.
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
.
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.
Now take a look at bug_presentation/src/persistence/models/banana.model.ts
, please.
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. If I comment these lines out then there is no loader exception.
Please take a look at bug_presentation/test/test.spec.ts
, lastly.
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
.
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.
This is a limitation of how TypeScript emits type metadata, and isn't an issue with reflect-metadata
itself. TypeScript's --emitDecoratorMetadata
does not handle forward or circular references in its metadata emit, which is why you will sometimes see undefined
.