typescriptmikro-orm

How to extend custom BaseRepository with Mikro ORM EntityRepository


I am trying to create a BaseRepository with custom methods that every repository should have. I have created my custom repository and extended it with EntityRepository but I get TS warning when trying to map the data to JSON.

This is the BaseRepository

import { AnyEntity, EntityName, EntityRepository, FilterQuery, SqlEntityManager } from '@mikro-orm/core';
    
export default abstract class BaseRepository<T extends AnyEntity<T>> extends EntityRepository<T> {
  protected readonly resource: string;
    
  protected constructor(_em: SqlEntityManager, entity: EntityName<T>) {
    super(_em, entity);
  }
    
  async listRecords(query: any, page: number, perPage: number) {
    try {
      const [results, count] = await this.findAndCount(
        <FilterQuery<any>>{},
        {
          limit: perPage,
          offset: (page - 1) * perPage
        }
      );
    
      const mappedData = await Promise.all(
        results.map(entity => {
          // THIS IS THE ERROR
          return entity.toJSON();
        })
      );
    
      return {
        rows: <EntityDTO<T>[]>mappedData
      };
    } catch (e) {
      throw e;
    }
  }
}

In the return entity.toJSON() I get the following error:

TS2339: Property  toJSON  does not exist on type  Loaded<T, never> 

And this my custom repository

export default class UserRepository extends BaseRepository<User> implements IUserRepository {
  protected readonly resource = 'users';
    
  constructor(protected readonly _em: SqlEntityManager) {
    super(_em, User);
  }
    
  async listUsers(query: ListUsersQuery) {
    const userEntities = await this.listRecords(query.filters, query.page, query.perPage);
    
    return new UserCollection(userEntities.rows, userEntities.meta, userEntities.links); // Assuming UserCollection class exists
  }
}

How can I adjust my types for the BaseRepository so typescript wouldn't complain about the method not existing?


Solution

  • There is no toJSON method on AnyEntity interface, so that's probably why. That method is actually also not present on the ORM BaseEntity anymore in v6, you don't really need it (neither you need to call it, it's called automatically when you serialize something via JSON.stringify which happens on higher levels, e.g. in some web server).

    Also, there is no reason for your Promise.all call, the methods are sync.

    I'd suggest you use wrap().toJSON() instead:

      async listRecords(query: any, page: number, perPage: number) {
        try {
          const [results, count] = await this.findAndCount(
            <FilterQuery<any>>{}, // this cast is probably not needed
            {
              limit: perPage,
              offset: (page - 1) * perPage
            }
          );
        
          const mappedData = results.map(entity => {
            return wrap(entity).toJSON();
          });
        
          return {
            rows: <EntityDTO<T>[]>mappedData // neither this one
          };
        } catch (e) {
          throw e;
        }
      }