如何在构建后从第三方依赖提取类型并生成类型文件?
从构建生成的第三方依赖中提取类型的实现思路
下面是几种可行的实现方案,适配你需要从构建后生成的第三方依赖(如@prisma/client)中提取类型并纳入自身源码的需求:
1. TypeScript 声明文件生成 + 简单脚本转换
先通过tsc生成目标类型的声明文件,再用脚本提取并转换为普通TS接口:
- 第一步:创建一个仅导出目标类型的入口文件,比如
extract-types.ts:export { Customer } from '@prisma/client'; - 第二步:运行
tsc命令生成声明文件:
这会在tsc extract-types.ts --declaration --emitDeclarationOnly --outDir ./temp-typestemp-types目录下生成extract-types.d.ts,里面包含Customer的完整类型定义。 - 第三步:写一个简单的Node脚本,读取
extract-types.d.ts内容,去掉declare关键字,整理成标准的TS接口文件:const fs = require('fs'); const content = fs.readFileSync('./temp-types/extract-types.d.ts', 'utf8'); // 提取Customer接口部分并处理格式 const customerInterface = content.match(/interface Customer {[\s\S]+?}/)?.[0]; if (customerInterface) { fs.writeFileSync('./src/Customer.ts', `export ${customerInterface}\n`); // 清理临时文件 fs.rmSync('./temp-types', { recursive: true }); } - 第四步:将上述步骤整合到项目构建脚本中,确保在
prisma generate之后执行。
2. 使用 ts-morph 操作 TypeScript AST
ts-morph是一个封装了TypeScript API的工具,可以更便捷地解析和生成TS代码:
- 安装依赖:
npm install ts-morph --save-dev - 编写提取脚本
generate-types.ts:import { Project } from 'ts-morph'; import fs from 'fs'; async function extractCustomerType() { const project = new Project(); // 加载Prisma生成的类型文件 const prismaSourceFile = project.addSourceFileAtPath('node_modules/@prisma/client/index.d.ts'); // 获取Customer接口 const customerInterface = prismaSourceFile.getInterface('Customer'); if (!customerInterface) { throw new Error('未找到Customer接口'); } // 生成目标TS文件内容 const interfaceContent = `export interface Customer { ${customerInterface.getProperties().map(prop => `${prop.getName()}: ${prop.getType().getText()};` ).join('\n ')}
}`;
// 写入文件 fs.writeFileSync('./src/Customer.ts', interfaceContent); console.log('Customer.ts 生成成功');
}
extractCustomerType().catch(err => console.error(err));
- 在`prisma generate`完成后,执行`node generate-types.ts`即可生成目标文件。 ## 3. 直接使用 TypeScript 官方 API 无需额外依赖,用TS官方API解析类型定义: - 确保已安装`typescript`依赖: ```bash npm install typescript --save-dev
- 编写脚本
extract-types.ts:import * as ts from 'typescript'; import fs from 'fs'; function extractCustomer() { const compilerOptions: ts.CompilerOptions = { target: ts.ScriptTarget.ESNext, module: ts.ModuleKind.CommonJS }; // 创建TS程序,加载Prisma的类型文件 const program = ts.createProgram(['node_modules/@prisma/client/index.d.ts'], compilerOptions); const typeChecker = program.getTypeChecker(); const prismaFile = program.getSourceFile('node_modules/@prisma/client/index.d.ts'); if (!prismaFile) throw new Error('未找到Prisma类型文件'); // 查找Customer导出符号 const prismaModuleSymbol = typeChecker.getSymbolAtLocation(prismaFile)!; const exports = typeChecker.getExportsOfModule(prismaModuleSymbol); const customerSymbol = exports.find(s => s.name === 'Customer'); if (!customerSymbol) throw new Error('未找到Customer类型'); // 提取属性和类型 const customerType = typeChecker.getTypeOfSymbolAtLocation(customerSymbol, customerSymbol.declarations![0]); const properties = customerType.getProperties(); // 生成接口代码 let interfaceCode = 'export interface Customer {\n'; properties.forEach(prop => { const propType = typeChecker.getTypeOfSymbolAtLocation(prop, prop.declarations![0]); interfaceCode += ` ${prop.getName()}: ${typeChecker.typeToString(propType)};\n`; }); interfaceCode += '}\n'; fs.writeFileSync('./src/Customer.ts', interfaceCode); } extractCustomer(); - 同样在
prisma generate后执行该脚本即可。
4. 自定义 Prisma 生成器
直接集成到Prisma的生成流程中,无需额外脚本步骤:
- 编写自定义生成器
prisma-custom-generator.ts:import { generatorHandler } from '@prisma/generator-helper'; import fs from 'fs'; import path from 'path'; // 映射Prisma类型到TS类型 function mapPrismaType(prismaType: string): string { const typeMap: Record<string, string> = { String: 'string', Int: 'number', Boolean: 'boolean', DateTime: 'Date', Float: 'number' }; return typeMap[prismaType] || prismaType; } generatorHandler({ onManifest() { return { defaultOutput: '../src/generated', prettyName: '自定义类型提取器' }; }, onGenerate(options) { // 从Prisma数据模型中找到Customer模型 const customerModel = options.dmmf.datamodel.models.find(m => m.name === 'Customer'); if (!customerModel) return; // 生成接口代码 let interfaceCode = 'export interface Customer {\n'; customerModel.fields.forEach(field => { const tsType = mapPrismaType(field.type); interfaceCode += ` ${field.name}: ${tsType}${field.isRequired ? '' : ' | null'};\n`; }); interfaceCode += '}\n'; // 写入文件 const outputPath = path.join(options.generator.output!.value, 'Customer.ts'); fs.mkdirSync(path.dirname(outputPath), { recursive: true }); fs.writeFileSync(outputPath, interfaceCode); } }); - 在
schema.prisma中添加该生成器:generator customTypes { provider = "ts-node ./scripts/prisma-custom-generator.ts" } - 运行
prisma generate时,会自动生成Customer.ts文件到指定目录。
内容的提问来源于stack exchange,提问作者TruMan1
相关产品推荐
相关产品推荐

