Skip to content

Commit a073b5e

Browse files
authored
fix: lookup up property descriptors on the prototype (#1258)
1 parent c0ec22a commit a073b5e

File tree

2 files changed

+58
-1
lines changed

2 files changed

+58
-1
lines changed

src/TransformOperationExecutor.ts

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -295,7 +295,7 @@ export class TransformOperationExecutor {
295295

296296
// if newValue is a source object that has method that match newKeyName then skip it
297297
if (newValue.constructor.prototype) {
298-
const descriptor = Object.getOwnPropertyDescriptor(newValue.constructor.prototype, newValueKey);
298+
const descriptor = this.getPropertyDescriptor(newValue.constructor.prototype, newValueKey);
299299
if (
300300
(this.transformationType === TransformationType.PLAIN_TO_CLASS ||
301301
this.transformationType === TransformationType.CLASS_TO_CLASS) &&
@@ -544,4 +544,12 @@ export class TransformOperationExecutor {
544544

545545
return this.options.groups.some(optionGroup => groups.includes(optionGroup));
546546
}
547+
548+
private getPropertyDescriptor(obj: any, key: PropertyKey): PropertyDescriptor | undefined {
549+
const descriptor = Object.getOwnPropertyDescriptor(obj, key);
550+
if (descriptor) return descriptor;
551+
552+
const prototype = Object.getPrototypeOf(obj);
553+
return prototype ? this.getPropertyDescriptor(prototype, key) : undefined;
554+
}
547555
}

test/functional/basic-functionality.spec.ts

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1664,6 +1664,55 @@ describe('basic functionality', () => {
16641664
expect(transformedUser).toEqual(likeUser);
16651665
});
16661666

1667+
it('should expose inherited method and accessors that have @Expose()', () => {
1668+
class User {
1669+
firstName: string;
1670+
lastName: string;
1671+
1672+
@Expose()
1673+
get name() {
1674+
return this.firstName + ' ' + this.lastName;
1675+
}
1676+
1677+
@Expose()
1678+
getName() {
1679+
return this.firstName + ' ' + this.lastName;
1680+
}
1681+
}
1682+
class Programmer extends User {
1683+
language: string;
1684+
}
1685+
1686+
const programmer = new Programmer();
1687+
programmer.firstName = 'Umed';
1688+
programmer.lastName = 'Khudoiberdiev';
1689+
programmer.language = 'en';
1690+
1691+
const fromPlainProgrammer = {
1692+
firstName: 'Umed',
1693+
lastName: 'Khudoiberdiev',
1694+
language: 'en',
1695+
};
1696+
1697+
const plainProgrammer: any = instanceToPlain(programmer);
1698+
expect(plainProgrammer).not.toBeInstanceOf(Programmer);
1699+
expect(plainProgrammer).toEqual({
1700+
firstName: 'Umed',
1701+
lastName: 'Khudoiberdiev',
1702+
language: 'en',
1703+
name: 'Umed Khudoiberdiev',
1704+
getName: 'Umed Khudoiberdiev',
1705+
});
1706+
1707+
const transformedProgrammer = plainToInstance(Programmer, fromPlainProgrammer);
1708+
expect(transformedProgrammer).toBeInstanceOf(Programmer);
1709+
const likeProgrammer = new Programmer();
1710+
likeProgrammer.firstName = 'Umed';
1711+
likeProgrammer.lastName = 'Khudoiberdiev';
1712+
likeProgrammer.language = 'en';
1713+
expect(transformedProgrammer).toEqual(likeProgrammer);
1714+
});
1715+
16671716
it('should transform array', () => {
16681717
defaultMetadataStorage.clear();
16691718

0 commit comments

Comments
 (0)