Search code examples
typescriptnestjsclass-validatorclass-transformer

ReferenceError: cannot access [*] before initialization. Validating nested objects with Class-validator in NestJs


I can't seem to understand what is going on here, or what i'm doing wrong, I've read other threads with similar issues, but didn't find one like mine (people are always asking about validating typed Arrays)

Here goes the class i want to validate.


export class CreateActivityDto {
   
    //other un-problematic validated properties

    @IsArray()
    @ValidateNested({ each: true })
    @Type(() => Plan)  
    plan: Plan[]  //this one works fine
    

    @IsObject()
    @IsDefined()
    @Type(() => Location) //imported from class-transformer
    location: Location
}
class Location {
    @IsString()
    @IsNotEmpty()
    address: string
    @IsObject()
    @Type(() => LatLng) //imported from class-transformer
    coords: LatLng
}

class LatLng {
    @IsNumber()
    lng: number
    @IsNumber()
    lat: number
}

Weirdly enough, if i declare location as an array of location (location: Location[]) it doesn't throw the error

This is being thrown in RunTime, few miliseconds after the server tries to bootstrap

[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

and this is my main.ts file

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();

In case there's any doubts, this an example of a valid object i could receive

{
"location": {
          "address": "Av. Corrientes 2003, Buenos Aires, Argentina",
          "coords": {
                    "lat": -34.6042967,
                    "lng": -58.39546360000001
               },
...other props,
}

Solution

  • If you change the order of declaration of these classes, it should work fine. I tested this on my local also:

    
    class LatLng {
        @IsNumber()
        lng: number;
        @IsNumber()
        lat: number;
    }
    
    class Location {
        @IsString()
        @IsNotEmpty()
        address: string;
        @IsObject()
        @Type(() => LatLng) //imported from class-transformer
        coords: LatLng;
    }
    export class CreateActivityDto {
        //other un-problematic validated properties
    
        @IsArray()
        @ValidateNested({ each: true })
        @Type(() => Plan)  
        plan: Plan[]  //this one works fine
    
        @IsObject()
        @IsDefined()
        @Type(() => Location) //imported from class-transformer
        location: Location;
    }
    

    As you might know, the decorators are usually run before other piece of code.