如何从对象数组中推断类型并保存以供项目使用?
自动生成杂乱API返回值的TypeScript类型方案
方案一:自定义Node.js脚本生成类型
自己编写逻辑遍历API返回的运行时数据,分析每个属性的所有可能类型,生成对应的TypeScript类型字符串并写入文件。适合简单场景,完全可控。
示例代码:
const fs = require('fs'); // 替换为实际从API获取的数据 const apiData = [ { title: "test", name: "Katy Smith" }, { title: ["ACNM", "AAF3"], name: "Mary Williams" }, { title: "test2", name: { firstName: "John", lastName: "Doe" } }, ]; // 分析数组元素,生成联合类型 function generateTypeFromArray(array) { if (!array.length) return '{}'; const propTypeSet = {}; array.forEach(item => { Object.entries(item).forEach(([prop, value]) => { const type = getValueType(value); if (!propTypeSet[prop]) propTypeSet[prop] = new Set(); propTypeSet[prop].add(type); }); }); const typeLines = Object.entries(propTypeSet).map(([prop, types]) => { const unionType = Array.from(types).join(' | '); return ` ${prop}: ${unionType};`; }); return `{\n${typeLines.join('\n')}\n}`; } // 递归获取值的TS类型字符串 function getValueType(value) { if (Array.isArray(value)) { if (value.length === 0) return 'unknown[]'; const elemType = getValueType(value[0]); return `${elemType}[]`; } if (typeof value === 'object' && value !== null) { const objTypeLines = Object.entries(value).map(([prop, val]) => { return ` ${prop}: ${getValueType(val)};`; }); return `{\n${objTypeLines.join('\n')}\n}`; } // 基础类型映射 const typeMap = { string: 'string', number: 'number', boolean: 'boolean', undefined: 'undefined', null: 'null' }; return typeMap[typeof value] || 'unknown'; } // 生成完整的TS类型导出代码 const typeCode = `export type ApiResponseItem = ${generateTypeFromArray(apiData)}`; fs.writeFileSync('./api-types.ts', typeCode, 'utf8');
方案二:使用现成工具库(推荐)
利用成熟的工具库直接从JSON数据生成TypeScript类型,无需自己编写复杂的类型分析逻辑,处理嵌套、联合类型更准确。比如quicktype,支持命令行和代码调用两种方式。
代码调用示例:
- 安装依赖:
npm install quicktype-core
- 编写生成脚本:
const { quicktype } = require('quicktype-core'); const fs = require('fs'); async function generateApiTypes() { // 替换为实际API返回数据 const apiData = [ { title: "test", name: "Katy Smith" }, { title: ["ACNM", "AAF3"], name: "Mary Williams" }, { title: "test2", name: { firstName: "John", lastName: "Doe" } }, ]; // 调用quicktype生成TS类型 const result = await quicktype({ inputJson: JSON.stringify(apiData), lang: 'typescript', topLevelName: 'ApiResponseItem', // 生成的类型名称 }); // 写入类型文件 fs.writeFileSync('./api-types.ts', result.lines.join('\n'), 'utf8'); } generateApiTypes();
运行脚本后,会生成符合需求的类型定义,自动处理联合类型和嵌套对象。
方案三:利用TypeScript Compiler API
借助TypeScript本身的类型推断能力,先将API数据作为常量写入临时文件,再通过TS Compiler API提取推断后的类型,最终生成类型文件。适合深度依赖TS的项目,生成的类型完全符合TS的推断规则。
示例代码:
import * as ts from 'typescript'; import * as fs from 'fs'; import * as path from 'path'; // 替换为实际API返回数据 const apiData = [ { title: "test", name: "Katy Smith" }, { title: ["ACNM", "AAF3"], name: "Mary Williams" }, { title: "test2", name: { firstName: "John", lastName: "Doe" } }, ]; // 创建临时TS文件,包含API数据常量和类型别名 const tempFilePath = path.join(__dirname, 'temp-api-data.ts'); const tempCode = ` const apiData = ${JSON.stringify(apiData)} as const; export type ApiResponseItem = typeof apiData[number]; `; fs.writeFileSync(tempFilePath, tempCode); // 初始化TS编译程序 const program = ts.createProgram([tempFilePath], { strict: true, target: ts.ScriptTarget.ESNext, }); // 遍历临时文件的AST,提取目标类型 const sourceFile = program.getSourceFile(tempFilePath)!; ts.forEachChild(sourceFile, node => { if (ts.isTypeAliasDeclaration(node) && node.name.text === 'ApiResponseItem') { const typeText = node.type.getText(sourceFile); const finalTypeCode = `export type ApiResponseItem = ${typeText};`; fs.writeFileSync('./api-types.ts', finalTypeCode, 'utf8'); } }); // 删除临时文件 fs.unlinkSync(tempFilePath);
运行这个TS脚本(需要ts-node或编译后执行),会生成准确的联合类型定义。
内容的提问来源于stack exchange,提问作者Pedro Dalla
相关产品推荐
相关产品推荐

