背景
最近接手了一个项目,虽然号称是用Typescript写的,可是我用ESLint检测了一下
json
"scripts": {
"code:fix": "eslint --fix \"src/**/*.{ts,tsx}\""
}
bash
yarn code:fix
发现检测出来的代码质量问题,基本上全是TS类型使用any定义。点开每个提示警告的文件看了一下,估算TS类型定义使用any定义占比在98%以上,真是有名无实呀。看下图 公司原本就有对这个项目的重构计划,一直因为各种事情耽搁下来。现在看到这种情况,立刻启动了重构计划。而我的任务就是填充项目缺失的ts类型定义。
发现问题
在补充ts类型定义时发现,有很大一部分缺失的ts类型定义是接口定义。之前使用过yapi-to-typescript
工具根据YApi
的接口定义生成 TypeScript接口类型定义。原本心里一阵窃喜,可以轻车熟路的完成这项工作任务。但随后问了一下后端,他们接口文档管理使用的是apifox,而yapi-to-typescript
只支持YApi或Swagger。看来原来的经验失效了。只能硬着头皮手动补全接口类型定义。却又发现apifox上的接口定义写的不规范,之前的后端开发偷懒,许多接口没写请求响应字段说明。如下图所示,空空如也。真是一波二折,事情做起来不顺畅。

解决问题
面对遇到的困难,我觉得社区应该有解决方案。抱着试试看的心态,带着问题上网搜了一下,果然有收获。找到了一个 在线JSON转typescript工具。可将json数据转换成TS类型定义。如果这个json数据是接口返回数据,目的不就达到了。虽然apifox上许多接口响应数据定义说明一片空白,可我可以直接访问线上的项目,在浏览器调试窗口,查看获取接口响应数据。 刚高兴了没几分钟,很快又发现,由于自己对刚接手的项目不熟,不知道该怎样操作,才能走到ts类型定义缺失的特定接口调用流程,获取到接口响应数据。遇到这种情况,自然而然的想到了postman这类工具。可以查看项目代码中调用接口的URL和参数,在postman这类工具中,手动发起接口调用请求,获取接口响应数据。这两个工具结合起来,就能丝滑柔顺的解决我面临的问题。
我之前已经安装过一个类似postman的浏览器扩展,如下图所示
用此工具,根据项目代码中调用的接口URL和参数,手动发起网络请求,就能方便的获取到ts类型定义缺失的接口响应数据。
把接口响应数据从浏览器中复制出来,粘贴到在线json转ts工具网站,点击json数据下方的复制按钮,就能获取期望的ts接口类型数据定义。稍微改改就能投入使用。经过思维的跳跃连接,困难迎刃而解。
探究原理
比较好奇,在线JSON转typescript工具网站,是怎么将json对象转换成ts类型定义的,感觉应该不难。可以用最质朴的思路,自己写一个。大致思路是ts类型用typeof判断,对象的键值还是对象的话,继续递归,再加上缩进美化功能,就写出了一个基础版本。
js
function jsonToTs(json, indent = 0) {
if (typeof json !== 'object' || json === null) return 'any';
if (Array.isArray(json)) {
if (json.length === 0) return 'any[]';
return `${jsonToTs(json[0], indent)}[]`;
}
const indentation = ' '.repeat(indent);
const lines = Object.entries(json).map(([key, value]) => {
let type;
switch (typeof value) {
case 'string':
type = 'string';
break;
case 'number':
type = 'number';
break;
case 'boolean':
type = 'boolean';
break;
case 'object':
type = jsonToTs(value, indent + 1);
break;
default:
type = 'any';
}
return `${indentation} ${key}: ${type};`;
});
return `{\n${lines.join('\n')}\n${indentation}}`;
}
// 示例
const json = {
name: 'Tom',
age: 25,
likes: ['code'],
profile: {
school: 'XYZ'
}
};
console.log('type Data = ' + jsonToTs(json));
测试了一下,输出符合预期
ts
type Data = {
name: string;
age: number;
likes: string[];
profile: {
school: string;
};
};
不过仍有改进的地方:1.无法生成取值是多个类型的情况。2.无法生成可选项。今天先到这里,后续有热情了再继续完善。