当前位置: 首页 > news >正文

JSON转TypeScript接口核心JS实现

JSON转TypeScript接口核心JS实现

这篇只讲核心 JS 逻辑:一段 JSON 是如何一步步变成 TypeScript 接口代码的。

在线工具网址:https://see-tool.com/json-to-typescript
工具截图:

1)状态与入口函数

先看最核心的状态和入口:

constjsonInput=ref('')constoutputData=ref('')constinterfaceName=ref('RootObject')constuseType=ref(false)constoptionalProps=ref(true)consterrorMessage=ref('')constconvert=()=>{constinput=jsonInput.value.trim()if(!input){outputData.value=''errorMessage.value=''return}try{constparsed=JSON.parse(input)if(parsed===null||(typeofparsed!=='object'&&!Array.isArray(parsed))){errorMessage.value='根节点必须是对象或数组'outputData.value=''return}constrootName=interfaceName.value.trim()||'RootObject'outputData.value=jsonToTypeScript(parsed,rootName)errorMessage.value=''}catch(error){errorMessage.value=`JSON 解析失败:${error.message}`outputData.value=''}}

这里做了三件事:输入清洗、JSON 解析、调用生成器。只要这一步跑通,工具就能稳定输出。

2)类型名生成:先合法,再去重

JSON 字段名常常不规范,比如有空格、短横线、数字开头,所以类型名要先标准化:

consttoPascalCase=(value,fallback='Item')=>{constcleaned=String(value||'').replace(/[^A-Za-z0-9_$\s]/g,' ').trim()if(!cleaned)returnfallbackconstparts=cleaned.split(/\s+/).filter(Boolean)constcombined=parts.map(part=>part.charAt(0).toUpperCase()+part.slice(1)).join('')return/^[A-Za-z_$]/.test(combined)?combined:fallback}constnormalizeInterfaceName=(value,fallback='RootObject')=>{if(!value)returnfallbackreturntoPascalCase(value,fallback)||fallback}

嵌套对象会不断生成新接口名,所以还要处理重名:

constinterfaceNames=newSet()constprocessedNames=newSet()constgenerateInterfaceName=(base,suffix='')=>{constbaseNormalized=normalizeInterfaceName(base,'RootObject')constsuffixNormalized=suffix?toPascalCase(suffix):''constname=`${baseNormalized}${suffixNormalized}`if(!interfaceNames.has(name)&&!processedNames.has(name)){interfaceNames.add(name)returnname}letcounter=2while(interfaceNames.has(`${name}${counter}`)||processedNames.has(`${name}${counter}`)){counter+=1}constfinalName=`${name}${counter}`interfaceNames.add(finalName)returnfinalName}

3)类型推断:递归处理对象和数组

真正的核心在inferType

constinferType=(value,key,parentName)=>{if(value===null)return'null'if(Array.isArray(value)){if(value.length===0)return'any[]'constelementTypes=newSet(value.map(item=>inferType(item,'Item',parentName)))consttypes=Array.from(elementTypes)constinner=types.length===1?types[0]:`(${types.join(' | ')})`return`${inner}[]`}if(typeofvalue==='object'){constnestedName=generateInterfaceName(parentName,key)processObject(value,nestedName)returnnestedName}if(typeofvalue==='string')return'string'if(typeofvalue==='number')return'number'if(typeofvalue==='boolean')return'boolean'return'any'}

比如[{ id: 1 }, { id: "2" }]会得到(RootItem | RootItem2)[]或联合类型形式,保证类型信息不丢。

4)对象转声明文本

推断完类型后,要拼成最终代码:

constformatPropertyKey=key=>{constvalue=String(key)constidentifier=/^[A-Za-z_$][A-Za-z0-9_$]*$/returnidentifier.test(value)?value:JSON.stringify(value)}constprocessObject=(obj,name)=>{if(processedNames.has(name))returnprocessedNames.add(name)constoptionalMark=optionalProps.value?'?':''constlines=[]lines.push(useType.value?`export type${name}= {`:`export interface${name}{`)Object.entries(obj).forEach(([key,value])=>{consttsType=inferType(value,key,name)constpropertyKey=formatPropertyKey(key)lines.push(`${propertyKey}${optionalMark}:${tsType};`)})lines.push('}')interfaces.push(lines.join('\n'))}

如果根节点本身是数组,再补一行根类型:

if(Array.isArray(json)){constarrayType=inferType(json,'Item',baseName)constrootLine=`export type${baseName}=${arrayType};`returninterfaces.length?`${interfaces.join('\n\n')}\n\n${rootLine}`:rootLine}

5)实时转换触发

输入实时更新,但不希望每敲一个字都立即解析,所以用了防抖:

letdebounceTimer=nullconstscheduleConvert=()=>{if(debounceTimer)clearTimeout(debounceTimer)debounceTimer=setTimeout(()=>{convert()},400)}watch(jsonInput,scheduleConvert)watch(interfaceName,scheduleConvert)watch([useType,optionalProps],convert)

最终效果就是:输入 JSON、改根接口名、切换interface/type、切换可选属性,结果区都会自动刷新。

6)完整思路总结

这套实现本质是三层:

  1. 输入层:解析 JSON、处理错误
  2. 推断层:递归判断数据类型、生成嵌套接口名
  3. 输出层:拼接 TypeScript 声明文本

把这三层拆开后,代码可读性会很高,读者也能很容易定位:哪里在“解析”、哪里在“推断”、哪里在“输出”。

http://www.jsqmd.com/news/395122/

相关文章:

  • OpenWrt 官方原版安装(PVE)
  • Apache Atlas实战:构建企业级元数据管理系统
  • 2025智能工作流AI优化引擎行业报告:各行业应用现状与未来趋势
  • 260214
  • VScode错误提示:command python-envs.runAsTask not found
  • 舌诊:藏在舌头上的健康密码
  • 你的舌头,藏着身体的秘密!用 EfficientNet 将三千年望诊智慧,变为可量化的现代科学
  • Buildroot使用外部编译工具链
  • 【机器学习】OpenCV高级图像处理深度解析:原理、实战与踩坑记录
  • 毕业论文智能写作工具指南:十大优选平台解析
  • 跨物种意义纠缠:AI元人文视域下的人类原始伙伴关系重构
  • 基于AI的论文写作工具推荐:十大可信平台综合测评
  • 学术论文AI创作工具推荐:十大优质平台横向评测
  • 毕业论文AI辅助平台盘点:十款实用工具详细对比
  • 寒假20
  • 虚拟零售中AI架构的多模态融合:如何结合文本、图像、语音提升体验?
  • AI系统监控预警中的异常检测:架构师实战——如何用算法提升准确率?
  • 打造AI原生应用领域多语言支持的强大系统
  • 【UI自动化测试】9_web自动化测试 _元素等待
  • 简述智慧校园系统架构及各层的主要功能
  • 智慧校园平台系统:2026年教育数字化转型的核心引擎
  • 一些做独立站 SEO 的案例以及关键词技巧
  • 智慧校园系统在教学、管理、安防和生活四大场景的落地实践
  • 智慧校园系统:学校数字化转型的“关键中枢”
  • 智慧校园系统如何构建?详解其“数据驱动”的五大核心应用场景
  • 【UI自动化测试】10_web自动化测试 _frame切换、多窗口切换
  • CrossOver 26重磅升级,跟我抢先体验CrossOver 26新特性吧 - 雨林谷
  • 2026 年春节档电影推荐:口碑必看《惊蛰无声》,全家 / 爸妈 / 朋友全场景观影指南 - SFMEDIA
  • [算法]dp优化
  • 并查集 - # [POJ 1182] 食物链