TurboRepo中使用Prisma方法时TypeScript导出类型不完整问题
TurboRepo + NestJS + Prisma 跨包类型推断失效解决方案
问题场景
在TurboRepo monorepo架构中,NestJS服务端包通过export.d.ts导出API相关类型时,前端包无法完整推断使用Prisma方法返回的类型,仅服务端包内部类型推断正常。具体表现为:
- 当服务端方法直接返回字面量对象时,前端包能正确推断类型
- 当服务端方法返回Prisma查询结果时,前端包中该类型被推断为
Promise<any>
服务端核心代码示例:
// export.d.ts import { AuthController } from './auth.controller'; import { SignInDto } from './auth.dto'; export * from './auth.controller'; type Wrapper<T extends (...args: any) => any> = Awaited<ReturnType<T>>; export namespace ApiTypes { export interface SignInPayload extends SignInDto {} export interface SignInResponse extends Wrapper<typeof AuthController.prototype.signin> { token: string } }
// auth.service.ts @Injectable() export class AuthService { constructor(private prisma: PrismaClient) {} async signin(payload: SignInDto) { return await this.prisma.staffUsers.findUnique({ where: { username: payload.identifier }, }); } }
原因分析
Prisma Client的返回类型是动态生成的内部类型,跨包传递时,前端包无法解析服务端包依赖的Prisma类型定义,导致TypeScript无法正确推断类型,最终退化为any。而直接返回字面量对象时,类型是显式的基础类型/自定义类型,能被跨包正确识别。
可行解决方案
方案1:显式指定服务层返回类型为Prisma模型类型
在服务层方法中,直接指定返回类型为Prisma自动生成的模型类型,让export.d.ts中的类型包装器能捕获到明确的类型:
// auth.service.ts import { Injectable } from '@nestjs/common'; import { PrismaClient, StaffUsers } from '@prisma/client'; // 导入Prisma模型类型 import { SignInDto } from './auth.dto'; @Injectable() export class AuthService { constructor(private prisma: PrismaClient) {} // 显式指定返回类型为Prisma生成的StaffUsers类型 async signin(payload: SignInDto): Promise<StaffUsers> { return await this.prisma.staffUsers.findUnique({ where: { username: payload.identifier }, }); } }
此方案利用Prisma自动生成的模型类型,无需手动维护复杂类型,当Prisma Schema更新时,类型会自动同步。
方案2:在export.d.ts中直接导入并复用Prisma模型类型
跳过从控制器方法推断类型的步骤,直接在export.d.ts中导入Prisma模型类型并组合:
// export.d.ts import { SignInDto } from './auth.dto'; import type { StaffUsers } from '@prisma/client'; // 导入Prisma模型类型 export namespace ApiTypes { export interface SignInPayload extends SignInDto {} // 直接复用StaffUsers类型并扩展token字段 export interface SignInResponse extends StaffUsers { token: string } }
此方案更直接,避免了依赖控制器方法的隐式类型推断,跨包类型传递更可靠。
方案3:优化服务端包TypeScript配置确保类型完整输出
调整服务端包的tsconfig.json,确保类型声明文件能完整包含Prisma相关类型:
{ "compilerOptions": { "declaration": true, // 生成类型声明文件 "declarationMap": true, // 生成类型映射,方便调试 "emitDeclarationOnly": false, // 确保类型和编译代码同时输出 "include": [ "src/**/*", "../prisma/**/*" // 包含Prisma生成的类型文件路径 ] } }
同时确保TurboRepo的turbo.json中,服务端包的构建任务能正确输出类型声明文件,前端包能正确依赖服务端包的类型输出。
总结
优先推荐方案1或方案2,既利用Prisma自动类型生成的优势,又能解决跨包类型推断失效的问题,维护成本极低。
内容的提问来源于stack exchange,提问作者KAVYA SHARMA
相关产品推荐
相关产品推荐

