如何基于实体关联泛化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
相关产品推荐
相关产品推荐

