From 3ecf59f5274b0c31794b4afb06fb0eaffcde9f3b Mon Sep 17 00:00:00 2001 From: kitimark Date: Sun, 12 Jan 2025 04:12:47 +0700 Subject: [PATCH] feat: add type arguments in transform decorator --- sample/sample6-type-arguments/app.ts | 17 ++++++++++++++ src/decorators/transform.decorator.ts | 4 ++-- .../metadata/transform-fn-params.interface.ts | 6 ++--- test/functional/custom-transform.spec.ts | 22 +++++++++++++++++++ 4 files changed, 44 insertions(+), 5 deletions(-) create mode 100644 sample/sample6-type-arguments/app.ts diff --git a/sample/sample6-type-arguments/app.ts b/sample/sample6-type-arguments/app.ts new file mode 100644 index 000000000..e496f0be2 --- /dev/null +++ b/sample/sample6-type-arguments/app.ts @@ -0,0 +1,17 @@ +import { plainToInstance, Transform } from '../../src'; + +interface CSVInvoiceRecord { + net: string; +} + +class Invoice { + @Transform(({ value }) => Number(value.replace(',', ''))) + net: number; +} + +const rawInvoice: CSVInvoiceRecord = { + net: '2,000', +}; + +const invoice = plainToInstance(Invoice, rawInvoice); +console.log(invoice); diff --git a/src/decorators/transform.decorator.ts b/src/decorators/transform.decorator.ts index dbaabeca0..6eb7ba79f 100644 --- a/src/decorators/transform.decorator.ts +++ b/src/decorators/transform.decorator.ts @@ -6,8 +6,8 @@ import { TransformFnParams, TransformOptions } from '../interfaces'; * * Can be applied to properties only. */ -export function Transform( - transformFn: (params: TransformFnParams) => any, +export function Transform = any, K extends keyof T = any, R = any>( + transformFn: (params: TransformFnParams) => R, options: TransformOptions = {} ): PropertyDecorator { return function (target: any, propertyName: string | Symbol): void { diff --git a/src/interfaces/metadata/transform-fn-params.interface.ts b/src/interfaces/metadata/transform-fn-params.interface.ts index dc6b9ab2a..a2c6bb610 100644 --- a/src/interfaces/metadata/transform-fn-params.interface.ts +++ b/src/interfaces/metadata/transform-fn-params.interface.ts @@ -1,10 +1,10 @@ import { TransformationType } from '../../enums'; import { ClassTransformOptions } from '../class-transformer-options.interface'; -export interface TransformFnParams { - value: any; +export interface TransformFnParams = any, K extends keyof T = any> { + value: T[K]; key: string; - obj: any; + obj: T; type: TransformationType; options: ClassTransformOptions; } diff --git a/test/functional/custom-transform.spec.ts b/test/functional/custom-transform.spec.ts index dea04fa57..7c801159a 100644 --- a/test/functional/custom-transform.spec.ts +++ b/test/functional/custom-transform.spec.ts @@ -783,6 +783,28 @@ describe('custom transformation decorator', () => { }).not.toThrow(); }); + it('should serialize json to invoice instance of class Invoice with type arguments', () => { + defaultMetadataStorage.clear(); + expect(() => { + interface CSVInvoiceRecord { + net: string; + } + + class Invoice { + @Transform(({ value }) => Number(value.replace(',', ''))) + net: number; + } + + const rawInvoice: CSVInvoiceRecord = { + net: '2,000', + }; + + const invoice = plainToInstance(Invoice, rawInvoice); + expect(invoice).toBeInstanceOf(Invoice); + expect(invoice.net).toEqual(2000); + }).not.toThrow(); + }); + it('should serialize a model into json', () => { expect(() => { instanceToPlain(model);