TypeORM使用findOne指定select时是否错误推断返回类型?
TypeORM中findOne指定select后关联实体的返回类型处理
场景说明:Quiz实体与Author实体通过@ManyToOne装饰器关联,Author包含id、name、age等属性。调用findOne时不传入select选项,返回类型为正确的Quiz类型(实体类直接作为类型使用);但传入select选项后,返回的quiz对象中author字段仅包含id,并非完整的Author对象,此时返回类型再用Quiz就不准确了。
我手动创建了以下映射类型来解决这个问题:
type TQuizWithAuthorJustId = { [Key in keyof Quiz]: Key extends 'author' ? Pick<Author, 'id'> : Quiz[Key]; };
但想知道这是不是唯一的解决办法?TypeORM就不能自动推断这种情况下的正确返回类型吗?我查阅了TypeORM文档,没找到相关内容。
回答:
首先明确:手动创建这类映射类型不是唯一解决方式,但TypeORM目前确实无法根据你传入的select选项,自动推断关联实体仅返回部分字段时的正确类型。
其他可行处理方式:
- 直接定义接口
如果Quiz实体的属性数量不多,可以直接编写接口描述返回结构:
interface QuizWithAuthorId { id: number; title: string; // 假设这是Quiz的属性 // 列出Quiz的所有属性,将author字段限定为仅含id的结构 author: { id: number }; }
这种方式的缺点是,若Quiz实体属性发生变更,接口需要手动同步,维护成本较高。
- 结合SelectQueryBuilder与类型断言
使用createQueryBuilder构建查询时,明确指定要选择的字段,再通过类型断言将结果转为自定义类型:
const quiz = await getRepository(Quiz) .createQueryBuilder('quiz') .select(['quiz.id', 'quiz.title', 'author.id']) .leftJoin('quiz.author', 'author') .where('quiz.id = :id', { id: 1 }) .getOne() as QuizWithAuthorId;
本质上还是需要手动定义目标类型,只是查询的写法不同。
为什么TypeORM无法自动推断?
TypeScript属于静态类型检查系统,无法根据运行时才确定的select参数(数组/对象)动态修改返回类型。TypeORM的findOne方法泛型默认绑定实体类类型,没有做更细粒度的条件类型推断,因此无法自动识别你仅选择了关联实体的id字段。
最优方案推荐
你最开始使用的映射类型是最优雅的方案,它能自动同步Quiz实体的属性变化,无需手动维护每个字段。如果后续需要处理更多类似的部分选择场景,还可以封装成通用工具类型:
type PartialEntity<T, K extends keyof T, P> = { [Key in keyof T]: Key extends K ? P : T[Key]; }; // 使用示例 type TQuizWithAuthorJustId = PartialEntity<Quiz, 'author', Pick<Author, 'id'>>;
内容的提问来源于stack exchange,提问作者leodevbro
相关产品推荐
相关产品推荐

