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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.26 12:02:12