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

如何基于实体关联泛化TypeORM的FindOptions类型?

问题描述

在不同的.repository.ts文件中调用TypeORM的find方法时,我会使用类似如下的配置对象:

const findOptions = {
  ...(search && {
    where: { name: ILike(`%${search}%`) },
  }),
};

随后执行await this.find(findOptions)。我已为该对象定义了基础的FindOptions接口:

import { FindOperator } from 'typeorm';

interface FindOptions {
  where: {
    name: FindOperator<string>;
  };
}

但当存在实体关联时,findOptions会包含关联相关属性,示例如下:

const findOptions: FindOptions = {
  relations: ['entityName'],
  ...(search && {
    where: { name: ILike(`%${search}%`) },
  }),
  ...(idArray && {
    where: {
      entityName: {
        id: In(idArray),
      },
      ...(search && {
        name: ILike(`%${search}%`),
      }),
    },
  }),
};

对应的类型需要手动添加关联实体相关字段:

import { FindOperator } from 'typeorm';

interface FindOptions {
  where: {
    name: FindOperator<string>;
    entityName: {
      id: FindOperator<string>;
    };
  };
  relations: string[];
}

我希望将FindOptions接口泛化,基于实体的关联自动推断类型,而非硬编码实体名称,比如尝试定义如下泛型接口:

import { FindOperator } from 'typeorm';

interface FindOptions<T> {
  where: {
    name: FindOperator<string>;
    [P in keyof T]: {
      id: FindOperator<string>;
    };
  };
  relations: string[];
}

其中T为实体类,示例实体如下:

@Entity({ name: 'myEntity' })
export class MyEntity {
  @PrimaryGeneratedColumn('uuid')
  id: string;

  @Column({ type: 'varchar' })
  name: string;

  @ManyToOne(() => AnotherEntity)
  @JoinColumn({ name: 'anotherEntityId', referencedColumnName: 'id' })
  anotherEntity: AnotherEntity;
}

理想状态下关联实体名称能自动替换为实体中的关联属性名(如anotherEntity),请问该如何实现?

实现方案

结合TypeORM内置类型与TypeScript的条件、映射类型,可以实现自动推断实体关联属性的泛型配置接口:

1. 定义关联属性筛选类型

先写一个条件类型,自动提取实体中属于关联实体的属性键(即类型为其他实体类的属性):

import { FindOperator, FindManyOptions, FindOptionsWhere } from 'typeorm';

// 筛选实体中属于关联实体的属性键
type EntityRelations<T> = {
  [P in keyof T]: T[P] extends { id: any } ? P : never;
}[keyof T];

// 构建关联属性的where条件类型
type RelationWhere<T> = {
  [P in EntityRelations<T>]?: {
    id: FindOperator<string>;
  };
};

2. 泛化的FindOptions接口

基于上述类型,扩展TypeORM原生的FindManyOptions,实现自动推断:

interface GenericFindOptions<T> extends Omit<FindManyOptions<T>, 'where'> {
  where: (FindOptionsWhere<T> & RelationWhere<T>) | (FindOptionsWhere<T> & RelationWhere<T>)[];
}

3. 使用示例

针对MyEntity直接传入泛型参数,即可自动识别anotherEntity这类关联属性:

// 自动推断where支持name、anotherEntity.id等字段
const findOptions: GenericFindOptions<MyEntity> = {
  relations: ['anotherEntity'],
  ...(search && {
    where: { name: ILike(`%${search}%`) },
  }),
  ...(idArray && {
    where: {
      anotherEntity: {
        id: In(idArray),
      },
      ...(search && {
        name: ILike(`%${search}%`),
      }),
    },
  }),
};

await this.find(findOptions);

核心逻辑说明

  • EntityRelations<T>遍历实体所有属性,仅保留类型包含id的属性(即关联实体),自动提取anotherEntity这类关联属性名。
  • RelationWhere<T>为每个关联属性生成{ id: FindOperator<string> }格式的查询条件类型。
  • 继承FindManyOptions<T>并替换where类型,既保留TypeORM原生配置项(如relations、skip),又实现关联属性的自动类型推断。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.13 01:39:56