TypeScript 类型错误:Prisma 类型不匹配、Schema 变了类型没变
Prisma + TypeScript 的类型体系
Prisma Client 生成的类型大致分几类:
| 类型类别 | 命名规则 | 例子 | |
|---|---|---|---|
| Model 类型 | 模型名(PascalCase) | User、Post | |
| 输入类型 | 模型名 + Action + Input | UserCreateInput、PostUpdateInput | |
| 查询参数类型 | 模型名 + FindManyArgs / WhereInput | UserFindManyArgs、PostWhereInput | |
| 关系筛选器 | 模型名 + RelationFilter | PostListRelationFilter | |
| 聚合类型 | `模型名 + (GroupBy | Aggregate)` | UserGroupBy、PostAggregate |
这些类型全部自动生成到 node_modules/.prisma/client/index.d.ts 里。
常见错误与排查
错误一:Schema 改了但类型没更新
现象:你在 Schema 里给 User 加了 age Int 字段,prisma generate 跑过了,但 TypeScript 还是说 user.age 不存在。
排查:
# 1. 确认 generate 确实跑成功了
npx prisma generate
# 2. 检查 node_modules/.prisma/client/index.d.ts 里有没有 age 字段
grep -r "age" node_modules/.prisma/client/index.d.ts
# 3. 如果 d.ts 里有但编辑器不识别 → 重启 TypeScript 服务器
# Ctrl+Shift+P → "TypeScript: Restart TS Server"
错误二:版本不一致
# 确认 prisma CLI 和 @prisma/client 版本一样
npm list prisma @prisma/client
# 不一样就统一
npm install prisma@5.18.0 @prisma/client@5.18.0 --save-exact
错误三:include / select 导致返回类型变了
// ❌ TypeScript 报错的情况
const user = await prisma.user.findUnique({
where: { id: 1 },
})
// 这里 user 的类型是 User | null(没有 posts)
const userWithPosts = await prisma.user.findUnique({
where: { id: 1 },
include: { posts: true },
})
// 这里类型变成了 User & { posts: Post[] } | null
// 两者类型不同,不能直接互换
解决:Prisma Client 自动为每种 include/select 组合生成精确类型。如果你的代码里需要同时支持两种情况,要么用不同的类型声明,要么用类型断言。
错误四:部分选择(select)的类型推断
const result = await prisma.user.findUnique({
where: { id: 1 },
select: { id: true, email: true },
})
// result 的类型是 { id: number; email: string } | null
// 不是 User 类型!
// 所以你不能写 result.name → TypeScript 会报错说 name 不存在
这是 Prisma 的正确行为——select 只选了部分字段,返回的类型也只有部分字段。好处是类型安全,缺点是如果你想把这个对象传给一个接受 User 类型的函数,TypeScript 会报错。
解决:
- 如果需要完整 User 类型 → 用
include: {}或不传 select/include - 如果只需要部分字段 → 写个独立的类型接口或直接用 Prisma 自动推断的类型
错误五:BigInt 类型
Prisma 的 BigInt 字段在 Prisma Client 里返回 JavaScript 的原生 BigInt 类型。BigInt 不能直接 JSON 序列化(JSON.stringify 会报错)。
解决:
// 方案一:手动转成 string
const user = await prisma.user.findUnique({ where: { id: 1 } })
const serialized = JSON.stringify(user, (key, value) =>
typeof value === 'bigint' ? value.toString() : value
)
// 方案二:Prisma 配置 serializaton
// 在 schema.prisma 的 generator 里:
generator client {
provider = "prisma-client-js"
}
// 然后在应用启动时:
import { PrismaClient } from '@prisma/client'
const prisma = new PrismaClient()
// Prisma 7 起支持 BigInt 自动转 string 输出
错误六:Decimal 类型
Decimal 字段返回 Prisma 自定义的 Decimal 类实例,不是普通 number。
import { Prisma } from '@prisma/client'
const product = await prisma.product.findUnique({ where: { id: 1 } })
// product.price 的类型是 Prisma.Decimal
// 转 number
const priceNumber = product.price.toNumber()
// 转 string
const priceString = product.price.toString()
手动导入 Prisma 生成的类型
有时你需要在应用里引用 Prisma 生成的类型:
import { Prisma, PrismaClient } from '@prisma/client'
// 用 Prisma 命名空间里的各种类型
function processUser(user: Prisma.UserCreateInput) {
// ...
}
// Prisma.UserCreateInput、Prisma.PostWhereInput 等都在这里
或者直接导入 Model 类型:
import { User, Post } from '@prisma/client'
// User 和 Post 是普通的 TypeScript interface
Prisma 7 对 TypeScript 的改进
Prisma 7 显著减少了需要 TypeScript 评估的类型数量(官方说减少了 98%)。这直接解决了两个老问题:
- 编辑器类型提示慢 — 大 Schema 下类型推断卡顿
- tsc 编译慢 — 项目里 Prisma 生成的类型让 tsc 花很多时间
升级到 Prisma 7+ 会明显改善 TypeScript 体验。