question: Transform decorator execute sequence
I was trying to...
class myDto {
@Transform(() => console.log('second transform'))
@Transform(() => console.log('first transform'))
name: string;
}
The problem: According to TypeScript document (https://www.typescriptlang.org/docs/handbook/decorators.html#decorator-composition), when multiple decorators apply to a single declaration, their evaluation is similar to function composition in mathematics.
So I expected it should print the following log:
first transform
second transform
but actually, it prints in reverse sequence.
I think the reason is src/MetadataStorage.ts function findMetadatas
https://github.com/typestack/class-transformer/blob/95541a404d6e4e84c26255e2ac2b2bb58bfcb52f/src/MetadataStorage.ts#L235
This function call the reverse() when it return.
return metadataFromAncestorsTarget
.slice()
.reverse()
.concat((metadataFromTarget || []).slice().reverse());
I want to know is this behavior is expected correctly due to any reason? or it is a bug?
I'm also confused on this issue since the order of validators is different from the order of transformers, I always can not stop myself to mix them up :)
i don't understand, why this was done? Why do they work in different orders?
ok, I got it. Since class-transformer transforms an object into a class, it fires earlier. class-validator validates the class, so its decorators fire after class-transformer. Well, you can validate the value before converting it directly in the Transformer decorator. If the value is invalid, then call the exceptionFactory method, or, in the case of NestJS, you can throw out an instance of the HttpErrorByCode class. An example of how I did this to transform and validate a string in bigint.
// create-user.dto.ts
export class CreateUserDto {
@IsNotExists([ 'user', 'tgid' ])
@TransformStringToBigInt()
@ApiProperty({ type: 'string' })
tgid: bigint;
}
import { Transform, TransformOptions } from 'class-transformer';
import { isIntString } from './IsIntString';
import { HttpErrorByCode } from '@nestjs/common/utils/http-error-by-code.util';
import { HttpStatus } from '@nestjs/common';
export const TransformStringToBigInt = (options: TransformOptions = {}) => {
return Transform(({ value, key }) => {
if (!isIntString(value)) {
throw new HttpErrorByCode[HttpStatus.BAD_REQUEST]([
`${key} the property must be a string consisting of numbers only`,
]);
}
return BigInt(value);
}, options);
};