带类型的关系与连接
对关系进行建模,确保连接结果具有正确类型。
带类型的关系与连接 是 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 反馈 — 无需本地设置。