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

fix: plainToInstance will throw an error when exposing a getter in the parent class #1257

Open
CodyTseng opened this issue Jul 1, 2022 · 6 comments
Labels
status: fixed Issues with merged PRs, but not released yet type: fix Issues describing a broken feature.

Comments

@CodyTseng
Copy link
Contributor

CodyTseng commented Jul 1, 2022

Description

Minimal code-snippet showcasing the problem

import { Expose, plainToInstance } from 'class-transformer'

class Person {
  firstName: string;
  lastName: string;

  @Expose()
  get name() {
    return this.firstName + ' ' + this.lastName;
  }

  say() {
    console.log(`My name is ${this.name}`);
  }
}

class Programmer extends Person {
  language: string;

  say() {
    console.log(`My name is ${this.name}. I'm a ${this.language} programmer.`);
  }
}

const programmer = plainToInstance(Programmer, {
  firstName: 'Umed',
  lastName: 'Khudoiberdiev',
  language: 'JavaScript',
});

programmer.say();

console.log(instanceToPlain(programmer));

Expected behavior

Output:

My name is Umed Khudoiberdiev. I'm a JavaScript programmer.
{
  firstName: 'Umed',
  lastName: 'Khudoiberdiev',
  language: 'JavaScript',
  name: 'Umed Khudoiberdiev'
}

Actual behavior

/****/node_modules/class-transformer/cjs/TransformOperationExecutor.js:309
                            newValue[newValueKey] = finalValue;
                                                  ^

TypeError: Cannot set property name of #<Person> which has only a getter
    at TransformOperationExecutor.transform (/****/node_modules/class-transformer/cjs/TransformOperationExecutor.js:309:51)
    at ClassTransformer.plainToInstance (/****/node_modules/class-transformer/cjs/ClassTransformer.js:27:25)
    at plainToInstance (/****/node_modules/class-transformer/cjs/index.js:38:29)
    at Object.<anonymous> (/****/index.js:31:60)
    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 Function.executeUserEntryPoint [as runMain] (node:internal/modules/run_main:77:12)
    at node:internal/main/run_main_module:17:47
@CodyTseng CodyTseng added status: needs triage Issues which needs to be reproduced to be verified report. type: fix Issues describing a broken feature. labels Jul 1, 2022
@hcg1023
Copy link

hcg1023 commented Aug 28, 2022

same problem

@zh3ngyuan
Copy link

zh3ngyuan commented Oct 13, 2022

same issue here

I saw the PR has been raised up, any idea when this can be merged?

@tonysamperi
Copy link

tonysamperi commented Jul 9, 2023

Damn I just discovered the same!

As workaround do I have to duplicate the getter on the extending class?
Although I'm almost sure this used to work in NestJS...probably I'm using their version of the class-transformer...
I'll update here...

For now I can Confirm that duplicating the getter with the decorators solved

@mtpultz1977
Copy link

mtpultz1977 commented Apr 3, 2024

In our application the Expose decorator wasn't working for getters. Nothing gets passed along. So we copied the getters into the DTO as properties to avoid the getter issue, added the Transform decorator to each property that needed it, and applied the OmitType to the extended entity which avoids the error you get for overriding a getter with a property. It isn't idle since you're overcoming strict type checks, but it's only to create a DTO which wouldn't have a getter in most cases (ie. passed to client), and you still have the inheriting DTO getting all the other entity properties applied since it will match it structurally:

export class ExampleDto extends OmitType(ExampleEntity, [] as const) {
  // ... removed for brevity

  @Transform(({ obj }) => obj.whatever !== ‘something’, { toClassOnly: true })
  public exampleField: boolean; // <--- is a getter in ExampleEntity that matches the Transform
}

@diffy0712 diffy0712 removed the status: needs triage Issues which needs to be reproduced to be verified report. label May 5, 2024
@NoNameProvided NoNameProvided added the status: fixed Issues with merged PRs, but not released yet label May 22, 2024
@diffy0712 diffy0712 removed their assignment Dec 21, 2024
@KikoCosmetics
Copy link

Who added the "status: fixed" label? It's not fixed...the problem still occurs if you don't replicate the decorators on the extended class...

@thatsgolden
Copy link

the README is very confusing

You can expose what your getter or method return by setting an @expose() decorator to those getters or methods:

import { Expose } from 'class-transformer';

export class User {
  id: number;
  firstName: string;
  lastName: string;
  password: string;

  @Expose()
  get name() {
    return this.firstName + ' ' + this.lastName;
  }

  @Expose()
  getFullName() {
    return this.firstName + ' ' + this.lastName;
  }
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
status: fixed Issues with merged PRs, but not released yet type: fix Issues describing a broken feature.
Development

No branches or pull requests

9 participants