Drizzle ORM嵌套Select查询存在类型错误,如何修复?
Drizzle ORM嵌套关联查询类型错误修复方案
问题背景
我编写了一段Drizzle ORM的嵌套关联查询代码,实际执行后能正确返回包含所有嵌套结构的数据,但在avatar字段附近出现TypeScript类型错误:
Object literal may only specify known properties, and photo does not exist in type
查询代码
const feedbacks = await drizzleClient .select({ ...getTableColumns(feedbackFirst), project: { ...getTableColumns(project), }, userFrom: { ...getTableColumns(users), userAbout: { ...getTableColumns(userAbout), avatar: { ...getTableColumns(avatars), photo: { ...getTableColumns(photos), } } } } }) .from(feedbackFirst) .innerJoin(project, eq(project.prid, feedbackFirst.prid)) .innerJoin(users, eq(users.uid, feedbackFirst.uidFrom)) .innerJoin(userAbout, eq(userAbout.uid, users.uid)) .innerJoin(avatars, eq(avatars.uid, users.uid)) .innerJoin(photos, eq(photos.phid, avatars.phid))
环境信息
webstorm 2023.3.4 ts 5 node 21.4.0 macos sonoma 14.4
错误原因
Drizzle的自动类型推导无法识别这种多层嵌套的手动关联结构,getTableColumns(avatars)返回的类型中并不包含photo属性,因此TypeScript会抛出属性不存在的错误,尽管实际查询能正确返回数据。
修复方案
方案一:使用Drizzle Relations定义表关联(推荐)
提前在表定义中用relations明确建立表之间的关联关系,让Drizzle自动推导正确的类型:
// 示例:给avatars表定义与photos的关联 export const avatars = pgTable('avatars', { uid: varchar('uid').references(() => users.uid), phid: varchar('phid').references(() => photos.phid), // 其他字段 }); export const photos = pgTable('photos', { phid: varchar('phid').primaryKey(), // 其他字段 }); // 定义关联关系 export const avatarsRelations = relations(avatars, ({ one }) => ({ photo: one(photos, { fields: [avatars.phid], references: [photos.phid], }), })); // 同理给其他表定义关联(如users与userAbout、userAbout与avatars等)
定义关联后,查询时的类型推导会自动识别嵌套的关联字段,无需手动处理类型。
方案二:手动声明返回类型并断言
如果不想提前定义关联,可以手动创建返回类型,再通过类型断言让TypeScript认可查询结构:
// 定义查询返回的类型结构 type FeedbackWithRelations = { ...typeof feedbackFirst.$inferSelect, project: typeof project.$inferSelect, userFrom: { ...typeof users.$inferSelect, userAbout: { ...typeof userAbout.$inferSelect, avatar: { ...typeof avatars.$inferSelect, photo: typeof photos.$inferSelect, }, }, }, }; // 查询时添加类型断言 const feedbacks = await drizzleClient .select({ ...getTableColumns(feedbackFirst), project: { ...getTableColumns(project), }, userFrom: { ...getTableColumns(users), userAbout: { ...getTableColumns(userAbout), avatar: { ...getTableColumns(avatars), photo: { ...getTableColumns(photos), }, }, }, }, }) .from(feedbackFirst) .innerJoin(project, eq(project.prid, feedbackFirst.prid)) .innerJoin(users, eq(users.uid, feedbackFirst.uidFrom)) .innerJoin(userAbout, eq(userAbout.uid, users.uid)) .innerJoin(avatars, eq(avatars.uid, users.uid)) .innerJoin(photos, eq(photos.phid, avatars.phid)) as Promise<FeedbackWithRelations[]>;
方案三:调整查询结构(不推荐,会改变返回数据格式)
将photo字段从avatar的嵌套结构中移出,放到平级位置,避免类型推导冲突:
const feedbacks = await drizzleClient .select({ ...getTableColumns(feedbackFirst), project: { ...getTableColumns(project), }, userFrom: { ...getTableColumns(users), userAbout: { ...getTableColumns(userAbout), ...getTableColumns(avatars), // 将avatar字段平级到userAbout中 photo: { ...getTableColumns(photos), }, }, }, }) .from(feedbackFirst) .innerJoin(project, eq(project.prid, feedbackFirst.prid)) .innerJoin(users, eq(users.uid, feedbackFirst.uidFrom)) .innerJoin(userAbout, eq(userAbout.uid, users.uid)) .innerJoin(avatars, eq(avatars.uid, users.uid)) .innerJoin(photos, eq(photos.phid, avatars.phid));
总结
最推荐使用方案一,因为Drizzle的Relations是官方设计用于处理关联查询类型推导的特性,不仅能解决当前的类型错误,还能让后续的关联查询更简洁、类型更安全。
内容的提问来源于stack exchange,提问作者Andreas
相关产品推荐
相关产品推荐

