首页
更多应用
Search
1
修改iview的标签为i-的形式而不是驼峰的形式
2,791 阅读
2
PHP微信和企业微信签名
2,522 阅读
3
在VUE中怎么全局引入sass文件
2,223 阅读
4
vscode硬件占用较高解决方案
2,017 阅读
5
解决Macos下storm系列IDE卡顿的问题
1,975 阅读
默认分类
JS
VUE
CSS
mac使用技巧
React
fastmock
登录
/
注册
Search
标签搜索
react
js
vue
vscode
nodejs
项目
代码
webpack
工具
nginx
小程序
css
fastmock
eslint
npm
http
vue-cli3
git
浏览器
const
fastmock技术社区
累计撰写
102
篇文章
累计收到
26
条评论
首页
栏目
默认分类
JS
VUE
CSS
mac使用技巧
React
fastmock
页面
更多应用
搜索到
1
篇与
的结果
2024-09-14
处理TS类型声明文件,保留指定key的类型声明
我的原始需求是这样的,写了一个nodejs命令行工具,工具的功能是,拉取后端接口导出的 postman.json 接口内容,通过接口中的入参出参数据,生成入参出参的TS类型声明文件,达到在ts业务代码中可以校验接口入参和出参类型的目的,postman.json的大致格式如下{ "item": [ { "item": [ { "item": [], "name": "WechatMiniAppNatureController", "description": "WechatMiniAppNatureController" } ], "name": "wpe-miniwe-recycle-srv-api", "description": "exported at 2024-09-09 15:17:40" }, { "item": [ { "item": [ { "request": { "method": "POST", "description": "", "header": [ { "key": "Content-Type", "value": "application/json", "type": "text", "description": "" } ], "body": { "mode": "raw", "options": { "raw": { "language": "json" } }, "raw": "{\n \"Id\": 0\n}" }, "url": { "path": [ "wechat", "rec", "v1", "nature", "apply", "taxRebateInfo" ], "query": [], "host": "{{wpe-miniwe-recycle-srv-web}}", "raw": "{{wpe-miniwe-recycle-srv-web}}/wechat/rec/v1/nature/apply/taxRebateInfo" } }, "response": [ { "name": "退税申请详情接口-Example", "originalRequest": { "method": "POST", "description": "", "header": [ { "key": "Content-Type", "value": "application/json", "type": "text", "description": "" } ], "body": { "mode": "raw", "options": { "raw": { "language": "json" } }, "raw": "{\n \"Id\": 0\n}" }, "url": { "path": [ "wechat", "rec", "v1", "nature", "apply", "taxRebateInfo" ], "query": [], "host": "{{wpe-miniwe-recycle-srv-web}}", "raw": "{{wpe-miniwe-recycle-srv-web}}/wechat/rec/v1/nature/apply/taxRebateInfo" } }, "code": 200, "_postman_previewlanguage": "json", "header": [ { "name": "date", "key": "date", "value": "周一, 09 9月 202415:17:40 GMT", "description": "The date and time that the message was sent" } ], "body": "{\n \"Response\": {\n \"RequestId\": \"\",\n \"Error\": {\n \"Code\": \"\",\n \"Message\": \"\"\n },\n \"Data\": {\n \"id\": 0,\n \"taxRebateNumber\": \"\", //退税申请序号\n \"natureRecordId\": \"\", //自然人档案号\n \"registryNumber\": \"\", //登记序号\n \"collectionItemCode\": \"\", //征收项目代码\n \"collectionItemName\": \"\", //征收项目名称\n \"collectionCode\": \"\", //征收品目代码\n \"taxBureauCode\": \"\", //主管税务所科分局代码\n \"taxAuthorityCode\": \"\", //主管税务机关代码\n \"taxAmountAuthorityCode\": \"\", //税款所属税务机关代码\n \"taxAmountAuthorityName\": \"\", //税款所属税务机关名称\n \"streetTownCode\": \"\", //街道乡镇代码\n \"taxAmount\": 0.0, //应退税额\n \"taxRate\": 0.0, //税率\n \"taxUuid\": \"\", //税票UUID\n \"eleTaxNumber\": \"\", //电子税票号码\n \"taxStartTime\": \"\", //税款所属期起\n \"taxEndTime\": \"\", //税款所属期止\n \"applyStatus\": 0,\n \"rebateStatus\": \"\",\n \"rebateStatusCn\": \"\",\n \"taxStatus\": 0,\n \"rejectReason\": \"\",\n \"bankCardNo\": \"\",\n \"createTime\": \"\"\n }\n }\n}" } ], "name": "退税申请详情接口" } ], "name": "WechatMiniAppTaxController", "description": "WechatMiniAppTaxController" }, { "item": [ { "request": { "method": "POST", "header": [ { "key": "Content-Type", "value": "application/json", "type": "text", "description": "" } ], "body": { "mode": "raw", "options": { "raw": { "language": "json" } }, "raw": "{\n \"QrId\": \"\"\n}" }, "url": { "path": [ "wechat", "rec", "v1", "operator", "inviteConfirm" ], "query": [], "host": "{{wpe-miniwe-recycle-srv-web}}", "raw": "{{wpe-miniwe-recycle-srv-web}}/wechat/rec/v1/operator/inviteConfirm" } }, "response": [ { "name": "operatorInviteConfirm-Example", "originalRequest": { "method": "POST", "header": [ { "key": "Content-Type", "value": "application/json", "type": "text", "description": "" } ], "body": { "mode": "raw", "options": { "raw": { "language": "json" } }, "raw": "{\n \"QrId\": \"\"\n}" }, "url": { "path": [ "wechat", "rec", "v1", "operator", "inviteConfirm" ], "query": [], "host": "{{wpe-miniwe-recycle-srv-web}}", "raw": "{{wpe-miniwe-recycle-srv-web}}/wechat/rec/v1/operator/inviteConfirm" } }, "code": 200, "_postman_previewlanguage": "json", "header": [ { "name": "date", "key": "date", "value": "周一, 09 9月 202415:17:40 GMT", "description": "The date and time that the message was sent" } ], "body": "{\n \"Response\": {\n \"RequestId\": \"\",\n \"Error\": {\n \"Code\": \"\",\n \"Message\": \"\"\n },\n \"Data\": false\n }\n}" } ], "name": "operatorInviteConfirm" } ], "name": "WechatMiniAppOperatorController", "description": "WechatMiniAppOperatorController" } ], "name": "wpe-miniwe-recycle-srv-web", "description": "exported at 2024-09-09 15:17:40" } ], "info": { "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json", "name": "wpe-miniwe-recycle-srv-20240909151740", "description": "exported at 2024-09-09 15:17:40" } }上面的接口文档中 接口地址为 /wechat/rec/v1/nature/apply/taxRebateInfo 的接口返回体,经过数据反解析后输出的Ts类型声明代码为export type TWechatRecV1NatureApplyTaxRebateInfoRess = { Code: number; Error: { Code: number; Message: string; }, RequestId: string; Data: { id: number; taxRebateNumber: string; natureRecordId: string; // ... 其他属性 } };上面的代码中,除了Data内的数据,其他的都是所有接口相同的属性内容,所以我需要处理生成的ts文件,只保留 Data 的类型描述。也尝试过好几种方案,主要有从源代码处理,在postman文件的response -> body 代码中处理完内容再去做反解析在生成的文件中通过字符串匹配去查找上面的方法中,主要都存在一个问题,就是postman源代码中,body包含了很多杂七杂八的内容,比如换行符,注释,还有转译字符,加上body内容的层级是不固定,这为我们做正则匹配带来了很多麻烦,所以兜兜转转想到了最终的解决方案,那就是使用AST的方法来处理生成的TS代码,这样在操作AST的过程中,babel 会帮我们处理好注释和其他不相关的内容。先show一下最终的代码// 要先安装下面的依赖 const parser = require('@babel/parser'); const traverse = require('@babel/traverse').default; const generate = require('@babel/generator').default; /** * 取出声明代码中指定key的interface代码 * 使用babel的抽象语法树转换,处理,生成代码 * @param typeCode ts代码 * @param rootName 根类型名 * @param keyName 属性名 * @returns 取出的代码 */ export const subInterfaceByKey = (typeCode: string, rootName: string, keyName: string): string => { // 从ts类型声明代码中取出指定key的interface代码,现将代码转换成ast const ast = parser.parse(typeCode, { sourceType: 'module', plugins: ['typescript'] }); let titleType = 'any'; // 从ast中找到指定key的接口,生成代码返回。 traverse(ast, { TSInterfaceDeclaration(path) { if (path.node.id.name === rootName) { const properties = path.node.body.body; const titleProperty = properties.find(prop => prop.key.name === keyName); // console.log(titleProperty.typeAnnotation); if (titleProperty) { titleType = generate(titleProperty.typeAnnotation).code; } } }, }); if (titleType !== 'any') { // 去掉类型前面的冒号和空格 return titleType.replace(/:\s/, ''); } return titleType; };上面的代码中,通过babel parser将要处理的代码转换成ast,然后通过 traverse 的 TSInterfaceDeclaration 勾子来处理ts interface 类型的代码,最后将处理后的代码生成好赋值给变量返回,处理后的声明文件内容就成了下面这个样子了export type TWechatRecV1NatureApplyTaxRebateInfoRess = { id: number; taxRebateNumber: string; natureRecordId: string; // 。。。其他属性 };至于为什么要用type而不是interface,原因是,Data 数据有可能不是一个对象,而是基础数据类型或数组,比如export type TWechatRecV1JodCancelCmbcBillRess = boolean;经过这次经验,我想以后再遇到这种代码处理的需求,我不会第一时间想到通过正则来处理,而是通过AST来处理了,即安全又逻辑清晰,
2024年09月14日
4 阅读
0 评论
0 点赞