TypeScript Academy · 课时

带类型的关系与连接

对关系进行建模,确保连接结果具有正确类型。

第 4 / 4 课13 个步骤

带类型的关系与连接 是 CoddyKit 上的免费 TypeScript Academy 课时。 这是第 4 节课,共 4 节。 你可以在下方免费阅读本课时的完整内容 — 然后在浏览器中使用内置代码编辑器和全天候 AI 导师进行实践。 这是 TypeScript Academy 学习路径的一部分,你的进度在网页和 CoddyKit 应用中同步。 TypeScript Academy 课程共包含 4 节课。

类型化关系与嵌套结果

真实架构包含关系:一个用户拥有许多 posts,一篇帖子属于一个用户。类型安全的对象关系映射器允许您声明这些关系,然后从关系查询中返回正确嵌套且带有类型的结果。

声明关系

除了表之外,您还要定义一个描述它们如何连接的关系对象。这些元数据同时为 SQL 生成和结果类型提供支持。

import { relations } from "drizzle-orm";

export const usersRelations = relations(users, ({ many }) => ({
  posts: many(posts),
}));

export const postsRelations = relations(posts, ({ one }) => ({
  author: one(users, {
    fields: [posts.authorId],
    references: [users.id],
  }),
}));

关系查询

查询 API 允许您使用 with 请求相关行。结果会将相关数据嵌套在关系名称下。

const result = await db.query.users.findMany({
  with: { posts: true },
});
// result: (User & { posts: Post[] })[]

one 与 many 决定类型形状

many 关系会产生一个数组;one 关系会产生一个单独的对象(或 null)。嵌套类型会匹配您声明的基数。

const r = await db.query.posts.findMany({
  with: { author: true },
});
// r: (Post & { author: User })[]   // author is a single object

选择关系中的列

您可以同时收窄父级行和嵌套行。结果类型会在每一层独立收窄。

const r = await db.query.users.findMany({
  columns: { id: true, name: true },
  with: {
    posts: { columns: { title: true } },
  },
});
// r: { id: number; name: string; posts: { title: string }[] }[]

使用类型化列进行手动连接

较底层的连接同样保持类型安全。连接谓词使用类型化列引用,而选择结果会决定扁平结果的形状。

const rows = await db
  .select({ author: users.name, title: posts.title })
  .from(posts)
  .innerJoin(users, eq(users.id, posts.authorId));
// rows: { author: string; title: string }[]

左连接会引入可空性

LEFT JOIN 可能产生缺失的右侧行,因此连接后的列在结果类型中会变为可空。对象关系映射器会自动反映这一点。

const rows = await db
  .select({ name: users.name, title: posts.title })
  .from(users)
  .leftJoin(posts, eq(posts.authorId, users.id));
// rows: { name: string; title: string | null }[]

嵌套结果与扁平结果

关系查询(findMany + with)会提供嵌套对象;手动连接会提供扁平行。需要对象图时请选择嵌套结果,需要表格投影时请选择扁平结果。

嵌套的类型化方式

关系元数据会在类型层面被读取。查询类型会将基础行与一个对象进行交集运算;该对象的键是请求的关系,每个关系都会根据其基数映射为数组类型或单个类型。

type WithPosts = User & { posts: Post[] };
// "many" -> Post[], "one" -> User (or User | null for optional)

深度嵌套的关系

关系可以组合。您可以请求某个关系的关系,类型也会以同样的深度进行嵌套,全部自动推断。

await db.query.users.findMany({
  with: { posts: { with: { comments: true } } },
});
// User & { posts: (Post & { comments: Comment[] })[] }

为什么这很重要

手动为嵌套连接结果编写类型既容易出错,又会逐渐偏离架构。根据已声明的关系派生类型,可以让对象图类型与 SQL 保持同步,因此重命名关系会成为编译错误,而不是生产环境中的意外问题。

快速检查

请测试您对类型化关系和连接的掌握程度。

回顾

您声明了关系,然后让对象关系映射器生成嵌套的类型化结果:many 提供数组,one 提供单个对象,部分选择会收窄每一层,LEFT JOIN 会引入可空性,深度嵌套的关系可以组合。关系元数据同时驱动 SQL 和结果类型,使二者保持同步。

免费开始

用 AI 导师学习 TypeScript — 免费

在浏览器中编写并运行真实代码,获得全天候 AI 导师的即时帮助,并在网页或应用中继续学习。

课程
101
课程
352

常见问题解答

「带类型的关系与连接」课时是免费的吗?

是的 — 「带类型的关系与连接」的完整文本可在网页上免费阅读。要进行交互式练习(内置代码编辑器和全天候 AI 导师)并解锁 TypeScript Academy 课程的其余内容,请升级到 CoddyKit PRO。 TypeScript Academy 课程共包含 4 节课。

「带类型的关系与连接」这节课中我会学到什么?

对关系进行建模,确保连接结果具有正确类型。 你通过在浏览器中直接运行的动手代码来练习 TypeScript Academy,全天候 AI 导师会在你学习这节课的过程中回答你的问题。

学习 TypeScript Academy 需要有经验吗?

无需任何先前经验。CoddyKit 上的 TypeScript Academy 课程适合初学者到高级学习者,你可以从这里开始或从头开始,按照自己的节奏学习。 这是第 4 节课,共 4 节。

「带类型的关系与连接」课时需要多长时间?

大多数 CoddyKit 课程大约需要 5–10 分钟。每节课都很精短且互动,所以你能稳步进步,并在网页和应用中从离开的地方继续。

我能在这节 TypeScript Academy 课中编写并运行代码吗?

能。每节 TypeScript Academy 课都包含内置代码编辑器,你可以在浏览器中直接编写并运行真实代码,并获得即时 AI 反馈 — 无需本地设置。

此课程中的所有课时

  1. 从模式到类型的映射
  2. 类型安全的查询构建
  3. 推断查询结果结构
  4. 带类型的关系与连接
← 返回 TypeScript Academy