class-transformer
class-transformer copied to clipboard
fix: Cast string to Boolean
Hi, I use class-transformer on NestJS and a cast problem occured during the conversion of the request payload.
Example :
{
"page": "1",
"limit": "1",
"isAnnotate": "false"
}
We got :
{
page: 1,
limit: 1,
isAnnotate: true
}
The defining class is :
class ArticleQuery {
page: number;
limit: number;
isAnnotate?: boolean
}
https://github.com/nestjs/nest/blob/master/packages/common/pipes/validation.pipe.ts#L96
When the plainToClass function was executed such as :
/*
* metatype => ArticleQuery
* value => { page: "1", limit: "1", isAnnotate: "false" }
* transformOptions => { enableImplicitConversion: true }
* /
classTransformer.plainToClass(metatype, value, this.transformOptions);
After a little digging, i found the caused into the function transform :
https://github.com/typestack/class-transformer/blob/develop/src/TransformOperationExecutor.ts#L108
} else if (targetType === Boolean && !isMap) {
if (value === null || value === undefined) return value;
return Boolean(value);
So i made a patch locally to solve the issue :
} else if (targetType === Boolean && !isMap) {
if (value === null || value === undefined) return value;
return value === "true";
Is it an attended behavior from the function to not convert a string "true"/"false" to a Boolean ?
Current version: 0.4.0
Best regards
@QuanticPotatoes - will this fix be committed into next official version?
"false" is true ... In my opinion, this should not be casted, correct type or transform annotation should be used.
@Transform(({ obj }) => {
return [true, 'enabled', 'true'].indexOf(obj.isAnnotate) > -1;
})
"false" is true ... In my opinion, this should not be casted, correct type or transform annotation should be used.
@Transform(({ obj }) => { return [true, 'enabled', 'true'].indexOf(obj.isAnnotate) > -1; })
Good Job!
I was looking for it! Is there any way to return an error if no "true" or "false" was sent? I think to accept any value (that not be true) as false is weird.
Other way could be use with class-validator:
@Transform(({ value }) => {
return [true, 'enabled', 'true'].indexOf(value) > -1;
})
@IsBooleanString()
isUnlocked: boolean;
but just does not work for me and I don't have any idea about what is happening When I use it with "IsBooleanString" decorator, I just receive, 400 bad request that says "isUnlocked must be a boolean string".
I would throw a 400 BAD REQUEST exception error if no "true" or "false" was sent.
"false" is true ... In my opinion, this should not be casted, correct type or transform annotation should be used.
@Transform(({ obj }) => { return [true, 'enabled', 'true'].indexOf(obj.isAnnotate) > -1; })
Your statement is "false"
@Transform(({ value }) => { return [true, 'enabled', 'true'].indexOf(value) > -1; }) @IsBooleanString()
After transforming value is boolean, not boolean-string. That's why u get error. Either make @IsBoolean() or remove @Transform()
I just want undefined not to be tranformed to false actually
Hey, guys. I'm in a similar place. Using @joanna-liana's answer, I've manage to work around like this:
// dto
@IsOptional()
@IsBoolean()
@Transform(({ value }) => {
if (value === 'true') return true;
if (value === 'false') return false;
return value;
})
private: boolean;
// controller
@UsePipes(
new ValidationPipe({
always: true,
}),
)
It's fishy, but it works.
I think a good argument for why 'false' should be treated as false is that class transformer gets used for parsing using requests and if the request is a GET and not a post all values get converted into strings thus false becomes 'false'. I'm having this trouble when using nestjs and doing GET requests. I use the qs lib to convert my request object qs.stringify(requestObject) which in the end my 'false' becomes true.
For me worked IsBooleanString decorator:
DTO:
@IsBooleanString()
@IsOptional()
isEnabled?: boolean
Controller:
@Get("/")
public async getEnabled(@Query(new ValidationPipe({ transform: true })) query: DTO) { ... }
Duplicate of https://github.com/typestack/class-transformer/issues/550.