Prisma 中文文档 下载 App

TypeScript 类型错误:Prisma 类型不匹配、Schema 变了类型没变

Prisma + TypeScript 的类型体系

Prisma Client 生成的类型大致分几类:

类型类别命名规则例子
Model 类型模型名(PascalCase)User、Post
输入类型模型名 + Action + InputUserCreateInput、PostUpdateInput
查询参数类型模型名 + FindManyArgs / WhereInputUserFindManyArgs、PostWhereInput
关系筛选器模型名 + RelationFilterPostListRelationFilter
聚合类型`模型名 + (GroupByAggregate)`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 会报错。

解决:

错误五: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%)。这直接解决了两个老问题:

  1. 编辑器类型提示慢 — 大 Schema 下类型推断卡顿
  2. tsc 编译慢 — 项目里 Prisma 生成的类型让 tsc 花很多时间

升级到 Prisma 7+ 会明显改善 TypeScript 体验。