Open nitinmagdumvista opened 1 year ago
+1 This problem...
"this" object all properties set to undefined when use new keyword.
version: 0.14.0
example code:
export class ClassValidatorDTO {
constructor(data: Record<string, any>) {
Object.assign(this, { ...data });
}
checkErrors() {
let errors = validateSync(this, { whitelist: true });
return errors;
}
}
export class UserCreateDTO extends ClassValidatorDTO {
@Length(3, 20)
username: string;
@Length(8, 32)
password: string;
@IsEmail()
email: string;
@Length(3, 20)
name: string;
@Length(3, 20)
surname: string;
}
let reqBody = new UserCreateDTO(data); // reqBody all props undefined now
console.dir({...reqBody}, {depth: null})
let errors = reqBody.checkErrors();
if (errors.length) console.log(errors)
console.dir({...reqBody})
I think it's a problem with typescript compile settings. target
I just got this error in es2022.
I can't reproduce whatever issue you seem to be describing here. Here's my attempt at reproducing your issue, and everything seems to work fine (your validator is just console.logging the field value, so there's really nothing that can go wrong there):
import { plainToInstance } from "class-transformer";
import {
registerDecorator,
validate,
ValidationArguments,
ValidationOptions,
ValidatorConstraint,
ValidatorConstraintInterface,
} from "class-validator";
// create Constraint
@ValidatorConstraint({ async: true })
export class ValidateEnumContsraint1 implements ValidatorConstraintInterface {
private error: string;
defaultMessage(validationArguments?: ValidationArguments): string {
return this.error;
}
validate(
value: any,
validationArguments?: ValidationArguments
): Promise<any> | boolean {
try {
console.log("value", value);
console.log("validationArguments", validationArguments);
return true;
} catch (e) {
this.error = `Error in input value for ${
validationArguments.property
} - ${JSON.stringify(e)}`;
return false;
}
}
}
// create decorator
export function ValidateFileDecorator(
enumName: any,
validationOptions?: ValidationOptions
) {
return function (object: any, propertyName: string) {
registerDecorator({
target: object.constructor,
propertyName: propertyName,
options: validationOptions,
constraints: [enumName],
validator: ValidateEnumContsraint1,
});
};
}
class MyClass {
@ValidateFileDecorator("banana")
file: unknown;
}
const plain = { file: "this is a file I guess" };
const instance = plainToInstance(MyClass, plain);
const errors = await validate(instance);
console.log(errors); // []
I think it's a problem with typescript compile settings. target
I just got this error in es2022.
I face up with same problem. And you are right! Option "target": "es2022" in tsconfig is reason. I tried downgrade to "es2021" - and undefined is gone.
Steps to reproduce with some controller file:
import { Controller, Post, Body } from '@nestjs/common';
import { IsOptional } from 'class-validator';
export class TestDto {
@IsOptional()
option1: string;
@IsOptional()
option2: string;
}
@Controller('test')
export class TestController {
@Post('/')
createTest(@Body() body: TestDto) {
/* Input body value is
{
option1: 'val1'
}
*/
console.log('----------Log test dto');
console.log(body);
// tsconfig with "target": "es2022" result is: TestDto { option1: 'val1', option2: undefined }
// tsconfig with "target": "es2021" result is: TestDto { option1: 'val1' }
return body;
}
}
Some package versions: nodejs v18.19.1 "class-validator": "^0.14.1", "@nestjs/common": "^9.3.12", "typescript": "~5.3.3"
Compiler options
{
"compilerOptions": {
"module": "commonjs",
"declaration": true,
"removeComments": true,
"experimentalDecorators": true,
"emitDecoratorMetadata": true,
"allowSyntheticDefaultImports": true,
"target": "es2022", // or es2021
"sourceMap": true,
"outDir": "./dist",
"baseUrl": "./",
"strictNullChecks": false,
"noImplicitAny": false,
"strictBindCallApply": false,
"forceConsistentCasingInFileNames": false,
"noFallthroughCasesInSwitch": false,
"incremental": true,
"skipLibCheck": true,
"strict": true
},
"exclude": [
"node_modules",
]
}
So reason is useDefineForClassFields option in tsconfig.
For target ES2022 or higher this option is "useDefineForClassFields": true
by default otherwise false
. After changing tsconfig to this:
{
"compilerOptions": {
//....some options
"module": "commonjs",
"target": "es2022",
"useDefineForClassFields": false,
//....some options
}
Problem is gone!
i want to validate the file type also if the file is provided or not i am writing custom validator but in both case with and without file its giving me value undefined
// ============ custom validator
`import { Injectable } from '@nestjs/common'; import { registerDecorator, ValidationArguments, ValidationOptions, ValidatorConstraint, } from '@nestjs/class-validator'; import { ValidatorConstraintInterface } from '@nestjs/class-validator/types/validation/ValidatorConstraintInterface';
// create Constraint @ValidatorConstraint({ async: true }) @Injectable() export class ValidateEnumContsraint1 implements ValidatorConstraintInterface { private error: string;
defaultMessage(validationArguments?: ValidationArguments): string { return this.error; }
validate(value: any, validationArguments?: ValidationArguments): Promise | boolean {
try {
console.log('value', value);
console.log('validationArguments', validationArguments);
return true;
} catch (e) {
this.error =
Error in input value for ${validationArguments.property} - ${JSON.stringify(e)}
; return false; } } }// create decorator export function ValidateFileDecorator(enumName: any, validationOptions?: ValidationOptions) { return function (object: any, propertyName: string) { registerDecorator({ target: object.constructor, propertyName: propertyName, options: validationOptions, constraints: [enumName], validator: ValidateEnumContsraint1, }); }; } `
//=================== validatore used inside DTO
@ValidateFileRequiredDecorator() @ApiProperty({ type: 'string', format: 'binary', required: true }) readonly file: Express.Multer.File;