在Monorepo中如何在前后端共享Drizzle推导类型?
前后端类型共享方案(基于pnpm+Turborepo)
针对你这种Drizzle查询自动推导类型、且类型频繁变更的场景,不用搞复杂的中间共享包手动维护,直接利用Turborepo的monorepo特性就能解决,给你几个落地的方案:
方案一:直接让前端依赖后端包的类型(最省心)
因为是monorepo结构,后端和前端都是子包,完全可以直接让前端导入后端导出的类型,不需要额外中转:
- 后端配置类型生成:在后端包的
tsconfig.json里开启compilerOptions.declaration: true,这样编译时会自动生成.d.ts类型声明文件。 - 明确导出类型:确保后端导出的是纯类型,比如你的代码里可以改成:
用export type ReviewDetail = Awaited<ReturnType<typeof getReviewsFeed>>[number];export type明确标记是类型导出,避免前端导入到运行时代码。 - 前端添加依赖:在前端包的
package.json中添加后端包的workspace依赖:"dependencies": { "@repo/backend": "workspace:*" } - 前端直接导入:在前端代码里直接用类型:
import type { ReviewDetail } from "@repo/backend"; // 比如在React组件里用 const renderReview = (review: ReviewDetail) => { // ... }; - Turborepo任务依赖配置:在
turbo.json里让前端的构建任务依赖后端的类型生成任务,确保后端代码变更后,前端能拿到最新类型:{ "pipeline": { "backend#build": { "outputs": ["dist/**/*.d.ts"] }, "frontend#build": { "dependsOn": ["backend#build"] } } }
方案二:自动同步类型到共享包(隔离后端依赖)
如果不想让前端直接依赖后端包,可以写个简单脚本自动把后端的类型同步到专门的共享类型包:
- 创建共享类型包:在monorepo根目录下新建
packages/types,初始化package.json和tsconfig.json。 - 写类型提取脚本:比如在后端包的
scripts/extract-types.js里,把后端导出的类型复制到共享包:const fs = require('fs'); const path = require('path'); // 读取后端生成的类型文件里的ReviewDetail类型 const backendDtsPath = path.join(__dirname, '../dist/types/index.d.ts'); const content = fs.readFileSync(backendDtsPath, 'utf8'); // 提取出ReviewDetail的类型定义(可根据实际情况调整正则) const reviewDetailType = content.match(/export type ReviewDetail = .+?;/s)[0]; // 写入共享包的index.ts fs.writeFileSync(path.join(__dirname, '../../packages/types/src/index.ts'), reviewDetailType); - 绑定到后端构建流程:在后端包的
package.json里,把脚本加到build命令之后:"scripts": { "build": "tsc && node scripts/extract-types.js" } - 前后端依赖共享包:前端和后端都在
package.json里添加"@repo/types": "workspace:*",然后直接导入类型即可。
方案三:利用Drizzle原生工具提取查询类型
Drizzle本身提供了inferSelectModel等工具,可以直接从表结构和查询中推导类型,你可以把查询的结构抽象出来,统一导出:
// 后端的types/query-types.ts import { inferSelectModel } from 'drizzle-orm'; import { reviews, users, business } from '../db/schema'; // 推导基础表类型 type Review = inferSelectModel<typeof reviews>; type User = inferSelectModel<typeof users>; type Business = inferSelectModel<typeof business>; // 组合成查询返回的嵌套类型 export type ReviewDetail = Review & { author: Pick<User, 'username'>; business: Business; };
这种方式可以和Drizzle的表结构同步,然后再通过方案一或方案二共享给前端。
内容的提问来源于stack exchange,提问作者raspace
相关产品推荐
相关产品推荐

