diff --git a/src/TransformOperationExecutor.ts b/src/TransformOperationExecutor.ts index fe1da8e32..2ccce958b 100644 --- a/src/TransformOperationExecutor.ts +++ b/src/TransformOperationExecutor.ts @@ -3,8 +3,8 @@ import { ClassTransformOptions, TypeHelpOptions, TypeMetadata, TypeOptions } fro import { TransformationType } from './enums'; import { getGlobal, isPromise } from './utils'; -function instantiateArrayType(arrayType: Function): Array | Set { - const array = new (arrayType as any)(); +function instantiateCollectionType(collectionType: Function): Array | Set { + const array = new (collectionType as any)(); if (!(array instanceof Set) && !('push' in array)) { return []; } @@ -32,14 +32,14 @@ export class TransformOperationExecutor { source: Record | Record[] | any, value: Record | Record[] | any, targetType: Function | TypeMetadata, - arrayType: Function, + collectionType: Function, isMap: boolean, level: number = 0 ): any { if (Array.isArray(value) || value instanceof Set) { const newValue = - arrayType && this.transformationType === TransformationType.PLAIN_TO_CLASS - ? instantiateArrayType(arrayType) + collectionType && this.transformationType === TransformationType.PLAIN_TO_CLASS + ? instantiateCollectionType(collectionType) : []; (value as any[]).forEach((subValue, index) => { const subSource = source ? source[index] : undefined; @@ -281,9 +281,10 @@ export class TransformOperationExecutor { } // if value is an array try to get its custom array type - const arrayType = Array.isArray(value[valueKey]) - ? this.getReflectedType(targetType as Function, propertyName) - : undefined; + const collectionType = + Array.isArray(value[valueKey]) || value[valueKey] instanceof Set + ? this.getReflectedType(targetType as Function, propertyName) + : undefined; // const subValueKey = TransformationType === TransformationType.PLAIN_TO_CLASS && newKeyName ? newKeyName : key; const subSource = source ? source[valueKey] : undefined; @@ -324,13 +325,13 @@ export class TransformOperationExecutor { // If nothing change, it means no custom transformation was applied, so use the subValue. finalValue = value[transformKey] === finalValue ? subValue : finalValue; // Apply the default transformation - finalValue = this.transform(subSource, finalValue, type, arrayType, isSubValueMap, level + 1); + finalValue = this.transform(subSource, finalValue, type, collectionType, isSubValueMap, level + 1); } else { if (subValue === undefined && this.options.exposeDefaultValues) { // Set default value if nothing provided finalValue = newValue[newValueKey]; } else { - finalValue = this.transform(subSource, subValue, type, arrayType, isSubValueMap, level + 1); + finalValue = this.transform(subSource, subValue, type, collectionType, isSubValueMap, level + 1); finalValue = this.applyCustomTransformations( finalValue, targetType as Function, diff --git a/test/functional/es6-data-types.spec.ts b/test/functional/es6-data-types.spec.ts index 81e02ed63..e767ff17e 100644 --- a/test/functional/es6-data-types.spec.ts +++ b/test/functional/es6-data-types.spec.ts @@ -102,6 +102,51 @@ describe('es6 data types', () => { }); }); + it('using Set as source value', () => { + defaultMetadataStorage.clear(); + + class User { + id: number; + name: string; + @Type(() => Set) + weapons: Set; + } + + const plainUser = { + id: 1, + name: 'Max Pain', + weapons: new Set(['knife', 'eagle', 'ak-47']), + }; + + const weapons = new Set(); + weapons.add('knife'); + weapons.add('eagle'); + weapons.add('ak-47'); + + const user = new User(); + user.id = 1; + user.name = 'Max Pain'; + user.weapons = weapons; + + const classedUser = plainToInstance(User, plainUser); + expect(classedUser).toBeInstanceOf(User); + expect(classedUser.id).toEqual(1); + expect(classedUser.name).toEqual('Max Pain'); + expect(classedUser.weapons).toBeInstanceOf(Set); + expect(classedUser.weapons.size).toEqual(3); + expect(classedUser.weapons.has('knife')).toBeTruthy(); + expect(classedUser.weapons.has('eagle')).toBeTruthy(); + expect(classedUser.weapons.has('ak-47')).toBeTruthy(); + + const plainedUser = instanceToPlain(user); + expect(plainedUser).not.toBeInstanceOf(User); + expect(plainedUser).toEqual({ + id: 1, + name: 'Max Pain', + weapons: ['knife', 'eagle', 'ak-47'], + }); + }); + it('using Map with objects', () => { defaultMetadataStorage.clear();