NestJS使用Class-validator验证嵌套对象时出现初始化前访问错误
问题:NestJS DTO嵌套对象类型报错“Cannot access 'Location' before initialization”
我在做NestJS的DTO验证时遇到了个奇怪问题:在CreateActivityDto里声明单个Location类型的location字段时,服务器启动后立刻抛出运行时错误,但改成数组类型Location[]就完全正常。查了相关讨论,大多是数组类型验证的问题,没找到匹配案例。
相关代码
export class CreateActivityDto { // 其他无问题的验证属性 @IsArray() @ValidateNested({ each: true }) @Type(() => Plan) plan: Plan[] // 这个完全正常 @IsObject() @IsDefined() @Type(() => Location) // 从class-transformer导入 location: Location // 这里会报错 } class Location { @IsString() @IsNotEmpty() address: string @IsObject() @Type(() => LatLng) // 从class-transformer导入 coords: LatLng } class LatLng { @IsNumber() lng: number @IsNumber() lat: number }
错误信息
[6:25:19 pm] Found 0 errors. Watching for file changes. [fullDirHere]\src\activity\dtos\activity.dto.ts:52 location: Location ^ ReferenceError: Cannot access 'Location' before initialization
main.ts配置
async function bootstrap() { const app = await NestFactory.create(AppModule, { cors: true }); app.useGlobalPipes(new ValidationPipe({ whitelist: true, transform: true, transformOptions: { enableImplicitConversion: true } })) await app.listen(3000); } bootstrap();
预期接收的有效请求体示例
{ "location": { "address": "Av. Corrientes 2003, Buenos Aires, Argentina", "coords": { "lat": -34.6042967, "lng": -58.39546360000001 } }, // 其他属性... }
解决方案
这个错误本质是JS/TS的变量提升机制导致的:CreateActivityDto类定义在Location和LatLng之前,运行时CreateActivityDto引用Location时,Location类还没完成初始化。
有两种简单的解决方式:
- 调整类的定义顺序
把LatLng和Location移到CreateActivityDto前面,让它们先被初始化:
class LatLng { @IsNumber() lng: number @IsNumber() lat: number } class Location { @IsString() @IsNotEmpty() address: string @IsObject() @Type(() => LatLng) coords: LatLng } export class CreateActivityDto { // 其他属性... @IsArray() @ValidateNested({ each: true }) @Type(() => Plan) plan: Plan[] @IsObject() @IsDefined() @Type(() => Location) location: Location }
- 拆分到单独文件导入
把Location和LatLng单独放到一个文件(比如location.dto.ts),然后在CreateActivityDto的文件中导入:
// location.dto.ts export class LatLng { @IsNumber() lng: number @IsNumber() lat: number } export class Location { @IsString() @IsNotEmpty() address: string @IsObject() @Type(() => LatLng) coords: LatLng } // activity.dto.ts import { Location } from './location.dto'; export class CreateActivityDto { // 其他属性... @IsObject() @IsDefined() @Type(() => Location) location: Location }
为什么数组类型不会报错?
当你声明Location[]时,TS编译后的运行时逻辑对类型的引用方式不同,不会直接触发对Location类的初始化检查;而单个Location类型会直接引用类本身,这时如果类还没初始化就会报错。
内容的提问来源于stack exchange,提问作者Marco Di Loreto
相关产品推荐
相关产品推荐

