joe*_*inz 5 typescript class-validator nestjs class-transformer
在我的 API 中考虑这个端点:
@Post('/convert')
@UseInterceptors(FileInterceptor('image'))
convert(
@UploadedFile() image: any,
@Body(
new ValidationPipe({
validationError: {
target: false,
},
// this is set to true so the validator will return a class-based payload
transform: true,
// this is set because the validator needs a tranformed payload into a class-based
// object, otherwise nothing will be validated
transformOptions: { enableImplicitConversion: true },
}),
)
parameters: Parameters,
) {
return this.converterService.start(image, parameters);
}
Run Code Online (Sandbox Code Playgroud)
设置为parameters参数的请求正文包含一个称为laserMode布尔类型的属性,它在参数 DTO上进行验证:
@IsDefined()
@IsBoolean()
public laserMode: boolean;
Run Code Online (Sandbox Code Playgroud)
现在是奇怪的部分,当从 PostMan 发送请求时:
laserMode = falselaserMode = cool (布尔值以外的字符串)我注意到,laserMode被始终设置为true,这是验证过程完成后,因为当我CONSOLE.LOG参数的实例在类的构造函数
export class Parameters {
...
constructor() {
console.log('this :', this);
}
...
}
Run Code Online (Sandbox Code Playgroud)
没看到属性啊!
注意:当
laserMode从请求中删除时,返回预期的验证错误(应定义,应为布尔值)。
// the logged instance 'this' in the constructor
this : Parameters {
toolDiameter: 1,
sensitivity: 0.95,
scaleAxes: 200,
deepStep: -1,
whiteZ: 0,
blackZ: -2,
safeZ: 2,
workFeedRate: 3000,
idleFeedRate: 1200,
laserPowerOn: 'M04',
laserPowerOff: 'M05',
invest: Invest { x: false, y: true }
}
// the logged laserMode value in the endpoint handler in the controller
parameters.laserMode in controller : true
// the logged laser value from the service
parameters.laserMode in service : true
Run Code Online (Sandbox Code Playgroud)
小智 51
找到了类转换器问题的解决方法
你可以使用这个:
@IsBoolean()
@Transform(({ value} ) => value === 'true')
public laserMode: boolean;
Run Code Online (Sandbox Code Playgroud)
这将根据字符串是“true”还是任何其他字符串将字符串转换为布尔值。一个简单的解决方法,但每个与 true 不同的字符串都会导致 false。
这就是我在设法保持布尔类型输入的同时解决问题的方法。
通过键引用原始对象而不是使用解构的值。
import { Transform } from 'class-transformer';
const ToBoolean = () => {
const toPlain = Transform(
({ value }) => {
return value;
},
{
toPlainOnly: true,
}
);
const toClass = (target: any, key: string) => {
return Transform(
({ obj }) => {
return valueToBoolean(obj[key]);
},
{
toClassOnly: true,
}
)(target, key);
};
return function (target: any, key: string) {
toPlain(target, key);
toClass(target, key);
};
};
const valueToBoolean = (value: any) => {
if (value === null || value === undefined) {
return undefined;
}
if (typeof value === 'boolean') {
return value;
}
if (['true', 'on', 'yes', '1'].includes(value.toLowerCase())) {
return true;
}
if (['false', 'off', 'no', '0'].includes(value.toLowerCase())) {
return false;
}
return undefined;
};
export { ToBoolean };
Run Code Online (Sandbox Code Playgroud)
export class SomeClass {
@ToBoolean()
isSomething : boolean;
}
Run Code Online (Sandbox Code Playgroud)
小智 8
你找到永久解决方案了吗?
我用这个 hack 解决了它:
@IsBoolean()
@Transform(({ obj, key }) => obj[key] === 'true')
laserMode: boolean;
Run Code Online (Sandbox Code Playgroud)
如果您想使用改进版本,@IsBoolean请执行以下操作:
@Transform(({obj, key}) => {
return obj[key] === 'true' ? true : obj[key] === 'false' ? false : obj[key];
})
@IsBoolean()
laserMode?: boolean = true;
Run Code Online (Sandbox Code Playgroud)
例如,如果有人发送,这将返回该值laserMode='anything'