Search code examples
javascriptnode.jstypescripttypeorm

Typescript entity circular reference got Class extends value undefined is not a constructor or null


So the back story is I'm working in a company and continued their code. I'm able to recreate the problem in a fresh nestjs project, so I have 4 entity (for demonstration purposes only)

// User Entity
import { Column, Entity, PrimaryGeneratedColumn, TableInheritance } from "typeorm";
import { PolymorphicChildren } from "typeorm-polymorphic";
import { AdvertEntity } from "./advert.entity";

@Entity('m_users')
@TableInheritance({ column: { type: "varchar", name: "type" } })
export class UserEntity{
    @PrimaryGeneratedColumn('uuid')
    id: string;

    @Column()
    name: string;

    @Column()
    email: string;

    @Column()
    password: string;

    @PolymorphicChildren(()=>AdvertEntity,{
        eager:false
    })
    adverts: AdvertEntity[];
}
// Employee Entity
import { ChildEntity, Column, JoinTable, ManyToMany } from "typeorm";
import { MerchantEntity } from "./merchant.entity";
import { UserEntity } from "./user.entity";

@ChildEntity()
export class EmployeeEntity extends UserEntity{
    @Column()
    room: string;

    @ManyToMany(()=>MerchantEntity)
    @JoinTable()
    merchants: MerchantEntity[];
}
// Merchant Entity
import { Entity, JoinTable, ManyToMany, PrimaryGeneratedColumn } from "typeorm";
import { PolymorphicChildren } from "typeorm-polymorphic";
import { AdvertEntity } from "./advert.entity";
import { EmployeeEntity } from "./employee.entity";

@Entity('m_merchants')
export class MerchantEntity{
    @PrimaryGeneratedColumn('uuid')
    id: string;

    @Column()
    name: string;

    @PolymorphicChildren(()=>AdvertEntity,{
        eager: false
    })
    adverts: AdvertEntity[];

    @ManyToMany(()=>EmployeeEntity)
    @JoinTable()
    employees: EmployeeEntity[];
}
// Adverts Entity
import { Column, Entity, PrimaryGeneratedColumn } from "typeorm";
import { PolymorphicParent } from "typeorm-polymorphic";
import { PolymorphicChildInterface } from "typeorm-polymorphic/dist/polymorphic.interface";
import { MerchantEntity } from "./merchant.entity";
import { UserEntity } from "./user.entity";

@Entity('m_adverts')
export class AdvertEntity implements PolymorphicChildInterface{

    @PrimaryGeneratedColumn('uuid')
    id: string;

    @Column()
    target: string;

    @PolymorphicParent(()=> [ UserEntity, MerchantEntity])
    owner: UserEntity | MerchantEntity;

    @Column()
    entityId: string;

    @Column()
    entityType: string;

}

When I ran these code I got this errors

export class EmployeeEntity extends UserEntity{
                                    ^
TypeError: Class extends value undefined is not a constructor or null
    at Object.<anonymous> (/Users/digitalenvision/sandbox/nest-sb-1/src/entity/employee.entity.ts:6:37)
    at Module._compile (node:internal/modules/cjs/loader:1103:14)
    at Object.Module._extensions..js (node:internal/modules/cjs/loader:1157:10)
    at Module.load (node:internal/modules/cjs/loader:981:32)
    at Function.Module._load (node:internal/modules/cjs/loader:822:12)
    at Module.require (node:internal/modules/cjs/loader:1005:19)
    at require (node:internal/modules/cjs/helpers:102:18)
    at Object.<anonymous> (/Users/digitalenvision/sandbox/nest-sb-1/src/entity/merchant.entity.ts:4:1)
    at Module._compile (node:internal/modules/cjs/loader:1103:14)
    at Object.Module._extensions..js (node:internal/modules/cjs/loader:1157:10)
digitalenvision@Digitals-MacBook-Pro-3 nest-sb-1 % npm run start

So the thing is that Merchant, Employee and Adverts has circular references between them. These issues went gone when I tried remove Merchant from the Polymorphic relation on AdvertsEntity, or I remove the many-to-many relation between Employee and Merchant. But we still need both many-to-many relation and the polymorphic relation. I tried a few solution from a few forum but still no luck for me. Any suggestion regarding these problem? Thanks


Solution

  • So I don't think it is possible to have polymorphic relation to a parent, my superior also think so. The solution was to have polymorphic relation with the child. Changing

    // User entity
    ...
    // remove these relation
    // @PolymorphicChildren(()=>AdvertEntity,{
    //        eager:false
    //    })
    //    adverts: AdvertEntity[];
    ...
    
    // Employee Entity
    ...
    // add the relation
    @PolymorphicChildren(()=>AdvertEntity,{
            eager: false
        })
        adverts: AdvertEntity[];
    ...
    
    // AdvertEntity
    ...
    // change to 
     @PolymorphicParent(()=> [ EmployeeEntity, MerchantEntity])
        owner: EmployeeEntity | MerchantEntity;
    ...
    

    solved my issue. thanks