You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何调整Mikro ORM自定义BaseRepository的TS类型解决toJSON报错?

问题

我尝试创建一个包含所有仓库通用自定义方法的BaseRepository,它继承自MikroORM的EntityRepository,但在调用实体的toJSON()方法映射数据时,出现了TypeScript类型错误。

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 => {
          // 此处触发TypeScript错误
          return entity.toJSON();
        })
      );
    
      return {
        rows: <EntityDTO<T>[]>mappedData
      };
    } catch (e) {
      throw e;
    }
  }
}

错误信息:

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

自定义仓库示例:

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); // 假设UserCollection类已定义
  }
}

如何调整BaseRepository的类型定义,消除这个TypeScript错误?

解决方案

方法1:使用MikroORM的wrap工具函数

MikroORM提供的wrap函数可以安全获取实体的操作方法,包括toJSON,同时解决类型推断问题:

  1. 先导入wrap:
import { AnyEntity, EntityName, EntityRepository, FilterQuery, SqlEntityManager, wrap } from '@mikro-orm/core';
  1. 修改映射逻辑(toJSON是同步方法,无需Promise.all):
const mappedData = results.map(entity => wrap(entity).toJSON());

方法2:显式断言实体类型

直接将Loaded<T, never>类型的实体断言为泛型T,因为Loaded是MikroORM的包装类型,底层实例就是你的实体类:

const mappedData = results.map((entity: T) => entity.toJSON());

方法3:强化泛型约束

在BaseRepository的泛型定义中,明确约束T必须包含toJSON方法,让TypeScript提前确认类型合法性:

interface WithToJSON {
  toJSON(): any;
}

export default abstract class BaseRepository<T extends AnyEntity<T> & WithToJSON> extends EntityRepository<T> {
  // 原有代码保持不变
}

方法4:优化返回值类型断言

返回rows时,替换原有类型断言为更准确的方式,避免类型不安全:

return {
  rows: mappedData as EntityDTO<T>[]
};

内容的提问来源于stack exchange,提问作者z0mbieKale

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.05 19:07:17