Search code examples
node.jstypescriptclassnestjsclass-transformer

class-transformer not wokring with array


I want to serialize a controller response but it's not working with array

UserSerialization

import { Role } from '@prisma/client';
import { Exclude, Expose } from 'class-transformer';

export const GROUP_USER_ME = 'GROUP_USER_ME';
@Exclude()
export class UserSerialization {
  @Expose({ groups: [GROUP_USER_ME] })
  id: string;
  @Expose({ groups: [GROUP_USER_ME] })
  email: string;
  @Expose({ groups: [GROUP_USER_ME] })
  name: string;
  @Expose({ groups: [GROUP_USER_ME] })
  createdAt: Date;
  @Expose({ groups: [GROUP_USER_ME] })
  updatedAt: Date;
  @Expose({ groups: [GROUP_USER_ME] })
  role: Role;

  constructor(partial: Partial<UserSerialization>) {
    Object.assign(this, partial);
  }
}

Controller

import { Role } from '@prisma/client';
import {
  GROUP_USER_ME,
  UserSerialization,
} from './serialization/user.serialization';
import {
  ClassSerializerInterceptor,
  Controller,
  Get,
  HttpCode,
  HttpStatus,
  Post,
  SerializeOptions,
  Session,
  UnauthorizedException,
  UseInterceptors,
} from '@nestjs/common';
import {
  SessionContainer,
} from 'supertokens-node/recipe/session';
import { AuthService } from './auth.service';
@Controller('auth')
@UseInterceptors(ClassSerializerInterceptor)
export class AuthController {
  constructor(private readonly authService: AuthService) {}

  @Get('/')
  @SerializeOptions({ groups: [GROUP_USER_ME] })
  async me(@Session() session: SessionContainer): Promise<UserSerialization> {
    const userID = session.getUserId();
    const users = await this.authService.allUsers(userID);
    if (!users) {
      await session.revokeSession();
      throw new UnauthorizedException();
    }

    return new UserSerialization(users);
  }
}

the porblem occurs on this new UserSerialization(users);, when I pass array I get this error Type 'User[]' has no properties in common with type 'Partial<UserSerialization>', however it works when I pass single user. So how I should make this work with array and without array?


Solution

  • Would it make sense to you if you had the following?

    export function square(num: number): number {
      return num * num;
    }
    
    
    const numbers = [1, 3, 5];
    console.log(square(numbers))
    

    It doesn't does it?


    You've told Typescript you expect to pass a single Partial<UserSerialization> to the UserSerialization constructor, but in your code you try to pass an array of User (User[]). Typescript is properly telling you "Hey, that's an array, this method only takes in a single object". So what do you do? You need to use a map to create a array of UserSerialization (UserSerialization[]) as the return of your method

      @Get('/')
      @SerializeOptions({ groups: [GROUP_USER_ME] })
      async me(@Session() session: SessionContainer): Promise<UserSerialization[]> {
        const userID = session.getUserId();
        const users = await this.authService.allUsers(userID);
        if (!users) {
          await session.revokeSession();
          throw new UnauthorizedException();
        }
    
        return users.map(user => new UserSerialization(user));
      }
    }
    

    If you are expecting to return a single object, then you need to update the return of your service code