类型安全:生成类型与 Prisma 类型工具
本教程共 54 篇 · 第 37 篇 · 更新于 2026-08-11 · 约 6 分钟阅读
本节目标:搞懂生成类型从哪来、长什么样,学会用它们约束自己的代码。
Prisma 的招牌是类型安全。Schema 是类型的唯一来源,改一处,全项目的类型跟着变。这一章把生成类型体系讲透:有哪些类型、怎么用、怎么派生自己的类型。
生成类型:Schema 的投影
每个模型都会生成一组类型,挂在 Prisma 命名空间下,从自定义 output 路径导入:
import { Prisma } from "./generated/prisma/client";
以 User 模型为例,UserSelect 描述 select 能选哪些字段:
const userEmail: Prisma.UserSelect = {
email: true,
};
写错字段名、给关系字段传了 boolean 之外的选项,编译期就报错。同一族类型还有 UserInclude、UserWhereInput、UserCreateInput、UserUpdateInput,分别对应 include、where、create、update 的参数形状。加上 UserFindManyArgs、UserDefaultArgs 这类按操作细分的类型,整套参数类型齐了。
输入类型特别适合放在接口层。API 的请求体类型直接用 Prisma.UserCreateInput,与数据库 Schema 严格对齐,少一类 bug:
async function createUser(data: Prisma.UserCreateInput) {
return prisma.user.create({ data });
}
多数时候类型由 TypeScript 自动推断,不用手写标注。需要标注的场合,用这些生成类型最稳。别忘了生成类型是编译期产物,它保证的是「类型正确」,不保证「数据合法」;运行时校验(比如 Zod)仍然需要。
类型系统原理:标量到 TS 的映射
每个标量类型都有固定的 TS 映射:
| Prisma 类型 | TS 类型 |
|---|---|
| String | string |
| Int / Float | number |
| Boolean | boolean |
| DateTime | Date |
| BigInt | bigint |
| Decimal | Prisma.Decimal |
| Bytes | Uint8Array |
| Json | JsonValue |
可选字段(?)映射为 string | null,列表字段([])映射为数组。DateTime 在代码里是 Date 对象,不要传字符串,否则运行时报错;Decimal 是 Prisma.Decimal 实例,专门解决浮点精度;Bytes 是二进制数组。原生类型属性 @db.* 只影响数据库里的列类型,不影响 TS 类型。比如 DateTime @db.Date 在数据库里是 date 列,TS 里仍然是 Date。内省(Introspection)时,非默认的数据库类型会自动补上 @db.* 标注。
部分结构类型:UserGetPayload + satisfies
查询结果常常只带部分字段或附加关系。手动定义这些类型,Schema 一改就得跟着改,维护成本高。正确做法是用 Prisma.UserGetPayload 配合 TypeScript 的 satisfies 从查询参数推导:
const userWithPosts = {
include: { posts: true },
} satisfies Prisma.UserDefaultArgs;
type UserWithPosts = Prisma.UserGetPayload<typeof userWithPosts>;
satisfies 先校验对象合法,再让类型推导拿到精确的字面量。UserDefaultArgs 换成 UserFindManyArgs、UserFindFirstArgs 同理。派生出的类型永远与 Schema 同步,Schema 加了字段,这里自动带上。
函数返回类型也能提取。先写函数,再用两个 TS 内置工具:
async function getUsersWithPosts() {
return prisma.user.findMany({ include: { posts: true } });
}
type UsersWithPosts = Awaited<ReturnType<typeof getUsersWithPosts>>;
ReturnType 拿到函数返回的 Promise 类型,Awaited 剥掉 Promise 外壳。改查询参数,类型自动跟着变,不用维护第二份。
PrismaPromise:可等待的查询
Prisma Client 的查询方法返回的不是普通 Promise,而是 PrismaPromise<T>。它是 thenable,可以直接 await,这点和 Promise 没有区别。额外能力是能被 $transaction 批量执行:
const queries: PrismaPromise<any>[] = [
prisma.user.update({ where: { id: 1 }, data: { name: "Alice" } }),
prisma.post.create({ data: { title: "Hello", authorId: 1 } }),
];
await prisma.$transaction(queries); // 全部成功或全部回滚
Note
$transaction只接受 PrismaPromise 数组,所以查询不能先 await 再传,要传未等待的查询对象。
UncheckedInput:安全版与直写版
create、update、upsert 的输入类型有两套。以 Post 为例:
// 安全版:通过关系字段连接作者
await prisma.post.create({
data: {
title: "Hello",
author: { connect: { id: 1 } },
},
});
// Unchecked 版:直接写外键
await prisma.post.create({
data: {
title: "Hello",
authorId: 1,
},
});
authorId 这种关系标量字段只存在于 PostUncheckedCreateInput 里。Unchecked 名字的由来:直接写外键绕过了关系层,类似「不检查」的快捷通道。它省事,但少了关系校验,报错信息也更含糊。安全版虽然嵌套更深,写出来的意图更清楚。官方建议优先用安全版输入类型,需要 connectOrCreate 之类的原子语义时它更好用。
四个类型工具
客户端扩展和泛型代码里,四个类型工具很常用:
| 工具 | 作用 |
|---|---|
Exact<Input, Shape> | 严格校验输入与目标形状一致 |
Args<Type, Operation> | 取某模型某操作的参数类型 |
Result<Type, Args, Operation> | 取某模型某操作的返回类型 |
Payload<Type, Operation> | 取结果的完整结构(标量与关系) |
Exact 用于收紧泛型参数,杜绝多余属性;Result 和 Args 搭配,能精确表达「输入这样、输出那样」的函数签名;Payload 用于在类型层面判断哪些键是标量、哪些是关系。它们都动态适配任何模型,是写共享扩展的利器。
最实用的是 Args。比如让函数的参数严格匹配 post.create:
type PostCreateBody = Prisma.Args<typeof prisma.post, "create">["data"];
async function addPost(postBody: PostCreateBody) {
return prisma.post.create({ data: postBody });
}
调用方传错字段,编译期立刻报错。第 36 章的 exists 扩展就是靠 Prisma.Args<T, "findFirst">["where"] 复用了 findFirst 的过滤条件类型,写扩展时这是标配。
用 Prisma.validator 校验复杂条件
动态拼 where 时,类型容易在中间步骤丢失。Prisma.validator 可以锚定类型,让中间变量也享受自动补全:
const whereClause = Prisma.validator<Prisma.UserWhereInput>()({
email: { contains: "@example.com" },
});
const users = await prisma.user.findMany({ where: whereClause });
后面的尖括号是必需的,它让 validator 的泛型参数指向目标类型。拼复杂过滤条件、把 where 拆到多个函数里时,这个工具很实用。
参考来源
- Prisma 官方文档:Type safety Overview
- Prisma 官方文档:How to use Prisma ORM’s type system
- Prisma 官方文档:Operating against partial structures of your model types
- Prisma 官方文档:Client extensions Type utilities