class-transformer
class-transformer copied to clipboard
fix: plainToInstance will throw an error when exposing a getter in the parent class
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
same problem
same issue here
I saw the PR has been raised up, any idea when this can be merged?
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
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
}