如何为NestJS DTO自动添加类型验证装饰器?
问题描述
我有一个包含数百个DTO的NestJS应用,示例DTO如下:
export class ExampleDto { id: number; name: string; createdAt: Date; data: MyType; ... }
需要实现whitelist + forbidNonWhitelisted的输入验证逻辑:收到与DTO结构不匹配的输入时,直接返回400错误请求异常。
用Nest官方的验证管道实现时,需要给每个属性手动添加@IsString()、@IsNumber()这类验证装饰器,但DTO数量太多,手动操作效率极低。想知道有没有办法让NestJS直接基于TypeScript类型做验证,或者有没有自动生成这些装饰器的方法?
解决方案
一、自动生成验证装饰器的工具
1. 用ts-auto-validate批量生成
这是一个专门根据TypeScript类型自动生成class-validator装饰器的工具,适合批量处理大量DTO:
- 安装开发依赖:
npm install ts-auto-validate --save-dev - 在项目根目录创建
ts-auto-validate.config.js,配置要扫描的DTO文件路径、输出目录等规则 - 执行命令批量生成带验证装饰器的DTO:
npx ts-auto-validate generate
生成后的DTO会自动带上对应类型的验证装饰器,不需要手动编写。
2. 自定义TS脚本实现
用ts-morph操作TypeScript AST,写一个脚本遍历所有DTO文件,根据属性类型自动添加装饰器。示例脚本如下:
import { Project, ClassDeclaration } from 'ts-morph'; // 初始化TS项目,指定DTO文件路径 const project = new Project(); project.addSourceFilesAtPaths('src/**/*.dto.ts'); // 遍历所有文件和类 project.getSourceFiles().forEach(sourceFile => { sourceFile.forEachChild(child => { if (!(child instanceof ClassDeclaration)) return; // 给类的每个属性添加对应装饰器 child.getProperties().forEach(property => { const typeText = property.getType().getText(); let decorators = []; switch(typeText) { case 'string': decorators.push('@IsString()'); break; case 'number': decorators.push('@IsNumber()'); break; case 'Date': decorators.push('@IsDate()'); break; case 'MyType': // 处理自定义类型 decorators.push('@ValidateNested()'); decorators.push('@Type(() => MyType)'); break; // 可以扩展更多类型的装饰器映射 default: return; } decorators.forEach(decorator => property.addDecorator(decorator)); }); // 自动导入所需的装饰器和工具 sourceFile.addImportDeclaration({ moduleSpecifier: 'class-validator', namedImports: ['IsString', 'IsNumber', 'IsDate', 'ValidateNested'] }); sourceFile.addImportDeclaration({ moduleSpecifier: 'class-transformer', namedImports: ['Type'] }); }); }); // 保存修改后的文件 project.saveSync();
运行这个脚本后,所有DTO的属性都会自动带上对应的验证装饰器。
二、开启全局验证管道配置
不管用哪种方式生成装饰器,最后都要在Nest全局管道中开启whitelist和forbidNonWhitelisted配置:
// main.ts async function bootstrap() { const app = await NestFactory.create(AppModule); app.useGlobalPipes( new ValidationPipe({ whitelist: true, // 自动过滤DTO中未定义的属性 forbidNonWhitelisted: true, // 遇到未定义属性时返回400错误 transform: true, // 自动将输入转换为DTO类型 }), ); await app.listen(3000); } bootstrap();
三、注意事项
- 自定义类型(如
MyType)需要确保对应的验证装饰器配置正确,比如@ValidateNested()和@Type()的组合是必须的 - 运行脚本前建议备份DTO文件,或者通过Git管理代码,避免意外覆盖
- 后续新增DTO时,重新运行脚本即可批量添加装饰器
内容的提问来源于stack exchange,提问作者Shtut
相关产品推荐
相关产品推荐

