Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Class constructor UserDto cannot be invoked without 'new' #411

Open
tolstenko opened this issue Feb 1, 2020 · 5 comments
Open

Class constructor UserDto cannot be invoked without 'new' #411

tolstenko opened this issue Feb 1, 2020 · 5 comments

Comments

@tolstenko
Copy link

tolstenko commented Feb 1, 2020

First of all, this lib is awesome!

I am facing the same problem of #378
Class constructor UserDto cannot be invoked without 'new'
TypeError: Class constructor UserDto cannot be invoked without 'new'
I modified the boilerplate https://github.com/NarHakobyan/awesome-nest-boilerplate adding the crud controller and crud service.

The main differences between your example and the implementation are:
I use an AbstractDto with a constructor that receives an AbstractEntity.
Here is the AbstractDto:

import { AbstractEntity } from '../abstract.entity';

export class AbstractDto {
  id: string;
  createdAt: Date;
  updatedAt: Date;

  constructor(entity: AbstractEntity) {
    this.id = entity.id;
    this.createdAt = entity.createdAt;
    this.updatedAt = entity.updatedAt;
  }
}

AbstractEntity:

import {
  CreateDateColumn,
  PrimaryGeneratedColumn,
  UpdateDateColumn,
} from 'typeorm';

import { UtilsService } from '../providers/utils.service';
import { AbstractDto } from './dto/AbstractDto';

export abstract class AbstractEntity<T extends AbstractDto = AbstractDto> {
  @PrimaryGeneratedColumn('uuid')
  id: string;

  @CreateDateColumn({
    type: 'timestamp without time zone',
    name: 'created_at',
  })
  createdAt: Date;

  @UpdateDateColumn({
    type: 'timestamp without time zone',
    name: 'updated_at',
  })
  updatedAt: Date;

  abstract dtoClass: new (entity: AbstractEntity, options?: any) => T;

  toDto(options?: any) {
    return UtilsService.toDto(this.dtoClass, this, options);
  }
}

And on top of that I create my dtos and entities:
UserDto

import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger';

import { RoleType } from '../../../common/constants/role-type';
import { AbstractDto } from '../../../common/dto/AbstractDto';
import { ProfileDto } from '../../profile/profile.dto';
import { UserEntity } from '../user.entity';

export class UserDto extends AbstractDto {
  @ApiPropertyOptional()
  firstName: string;

  @ApiPropertyOptional()
  lastName: string;

  @ApiPropertyOptional({ enum: RoleType })
  role: RoleType;

  @ApiPropertyOptional()
  email: string;

  constructor(user: UserEntity) {
    super(user);
    this.firstName = user.firstName;
    this.lastName = user.lastName;
    this.role = user.role;
    this.email = user.email;
  }
}

UserEntity

import { Column, Entity, Index } from 'typeorm';

import { AbstractEntity } from '../../common/abstract.entity';
import { RoleType } from '../../common/constants/role-type';
import { UserDto } from './dto/user.dto';
import { PasswordTransformer } from './password.transformer';

@Entity({ name: 'users' })
export class UserEntity extends AbstractEntity<UserDto> {
  @Column({ nullable: true })
  firstName: string;

  @Column({ nullable: true })
  lastName: string;

  @Column({ type: 'enum', enum: RoleType, default: RoleType.USER })
  role: RoleType;

  @Index('email')
  @Column({ unique: true, nullable: true })
  email: string;

  @Column({ nullable: true, transformer: new PasswordTransformer() })
  password: string;

  dtoClass = UserDto;
}

I found some descriptions indicating that I need to change the tsconfig.json target to at least ES6, but it is already there.

My option is to not use a dtos with constructors, right? Will I need to create another dto just for this scenario like the other dto but without constructor? Or could you provide an example using dtos with constructors?

Thanks in advance

@michaelyali
Copy link
Member

It seems to be a TypeScript issue. Make sure the target in your tsconfig.json is es6 or higher

@douglance
Copy link

@tolstenko Did you resolve this issue?

@valerybugakov
Copy link

@tolstenko @douglance did you resolve this question? [2]

@valerybugakov
Copy link

adding @Exclude() to dtoClass helped me to resolve the issue:

  // src/common/abstract.entity.ts

  @Exclude()
  abstract dtoClass: new (entity: AbstractEntity, options?: any) => T

@Germano123
Copy link

I'm using the updated version of awesome boilerplate. It's incredible :D

I'm facing a similar issue :S using the abstract entities and abstract dtos. Even updating the target to ES6 didn't help :S The problem is: using typeorm update in an entity causes it to break, even using @exclude() property in dtoClass variable in AbstractEntity it still is assuming the need of the dtoClass variable.

The update code should be similar to this:

async update(dataId: string, data: DataEntity): Promise<DataEntity> {
  await dataRepository.update(dataId, data); // the problem lies here in data
  return await dataRepository.find(dataId);
}

image

I've tried to break the solution in typeorm save method which is not the best solution, but still got the same error :S

The code should look like this.

async updateWithSave(dataId: string, data: DataEntity): Promise<DataEntity> {
  let dataEntity = await this.repo.find(dataId);
  dataEntity = { ...dataEntity, ...data, id: dataId, toDto: any }; // the problem lies here in data
  return await this.repo.save(dataEntity);
}

The error is: "EntityColumnNotFound: No entity column "dtoClass" was found."

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants