typescript - TypeORM OneToMany causa "ReferenceError: Cannot access '' before initialization"
Tengo dos entidades: Usuario y Hábito. Un usuario puede crear múltiples Hábitos, por lo tanto utilizo una relación UnoAMuchos en el Usuario (y MuchosAUno en el Hábito, respectivamente).
Entidad de Usuario
import {Entity, PrimaryGeneratedColumn, Column, CreateDateColumn, UpdateDateColumn, BeforeInsert, BeforeUpdate, OneToMany} from "typeorm";
import * as bcrypt from "bcryptjs";
import { Habit } from "../habits/habits.entity";
@Entity()
export class User {
@PrimaryGeneratedColumn("uuid")
id: string;
@Column()
name: string;
@Column()
email: string;
@Column()
password: string;
@OneToMany(type => Habit, habit => habit.author)
habits: Habit[];
@CreateDateColumn()
dateCreated: Date;
@UpdateDateColumn()
dateUpdated: Date;
@BeforeInsert()
@BeforeUpdate()
async hashPassword(): Promise<void> {
this.password = await bcrypt.hash(this.password,10);
}
async comparePassword(password: string): Promise<boolean> {
return bcrypt.compare(password, this.password);
}
constructor(props: any) {
Object.assign(this, props);
}
}
Entidad de hábito
import {Column, CreateDateColumn, Entity, PrimaryGeneratedColumn, UpdateDateColumn, ManyToOne} from "typeorm";
import { User } from "../users/users.entity";
@Entity()
export class Habit {
@PrimaryGeneratedColumn("uuid")
id: string;
@Column()
name: string;
@Column({ nullable: true})
description?: string;
@ManyToOne(type => User, user => user.habits)
author: User;
@CreateDateColumn()
dateCreated: Date;
@UpdateDateColumn()
dateUpdated: Date;
constructor(props: Partial<Habit>) {
Object.assign(this, props);
}
}
Problema
Al configurar la relación anterior recibo el siguiente error
WARNING in Circular dependency detected:
apps\api\src\habits\habits.entity.ts -> apps\api\src\users\users.entity.ts -> apps\api\src\habits\habits.entity.ts
WARNING in Circular dependency detected:
apps\api\src\users\users.entity.ts -> apps\api\src\habits\habits.entity.ts -> apps\api\src\users\users.entity.ts
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "User", function() { return User; });
^
ReferenceError: Cannot access 'User' before initialization
at Module.User (...\dist\apps\api\main.js:1782:96)
at Module../apps/api/src/habits/habits.entity.ts (...\dist\apps\api\webpack:\apps\api\src\habits\habits.entity.ts:42:13)
at __webpack_require__ (...\dist\apps\api\webpack:\webpack\bootstrap:19:1)
at Module../apps/api/src/users/users.entity.ts (...\dist\apps\api\main.js:1790:79)
at __webpack_require__ (...\dist\apps\api\webpack:\webpack\bootstrap:19:1)
at Module../apps/api/src/config/db-config.service.ts (...\dist\apps\api\main.js:1038:77)
at __webpack_require__ (...\dist\apps\api\webpack:\webpack\bootstrap:19:1)
at Module../apps/api/src/config/config.module.ts (...\dist\apps\api\main.js:978:76)
at __webpack_require__ (...\dist\apps\api\webpack:\webpack\bootstrap:19:1)
at Module../apps/api/src/app/app.module.ts (...\dist\apps\api\main.js:147:79)
Nota
Uso Nx y he creado una aplicación NestJS. La versión de TypeOrm es "^0.2.22" y la versión de @nestjs/typeorm es "^6.2.0"
Mi tsconfig es el siguiente:
{
"compileOnSave": false,
"compilerOptions": {
"rootDir": ".",
"sourceMap": true,
"declaration": false,
"moduleResolution": "node",
"emitDecoratorMetadata": true,
"experimentalDecorators": true,
"importHelpers": true,
"target": "es2015",
"module": "esnext",
"typeRoots": ["node_modules/@types"],
"lib": ["es2018", "dom"],
"skipLibCheck": true,
"skipDefaultLibCheck": true,
"baseUrl": ".",
"paths": {
"@awhile/contracts": ["libs/contracts/src/index.ts"],
"@awhile/ui": ["libs/ui/src/index.ts"]
}
},
"exclude": ["node_modules", "tmp"]
}
He intentado usar una relación ManyToMany y funcionó. Además, en una aplicación NestJS separada (sin Nx) no puedo reproducir este error de referencia. Cambiar la versión de target de ECMAScript en el tsconfig.json tampoco funcionó.
Ambas entidades solo se utilizan en sus servicios y no se instancian en ningún otro lugar.
Agradezco cualquier ayuda. Gracias de antemano.
Respuesta #1
Utiliza el contenedor de tipo Relation para evitar problemas de dependencia circular, como se describe aquí.
Por ejemplo:
import {Entity, OneToMany, Relation} from "typeorm";
import {Habit} from "../habits/habits.entity";
@Entity()
export class User {
...
@OneToMany(type => Habit, habit => habit.author)
habits: Relation<Habit>[];
...
}
Respuesta #2
En tsconfig, configurar el objetivo a "esnext" y el módulo a "commonjs" solucionó el problema para mí
{
"extends": "../../tsconfig.json",
"compilerOptions": {
"types": ["node", "jest"],
"emitDecoratorMetadata": true,
"experimentalDecorators": true,
"module": "commonjs",
"target": "esnext"
},
"include": ["**/*.ts"]
}
