TypeScript简介
TypeScript(TS)是一种强类型的编程语言,因为在编译时便会发现代码存在的问题,被前端团队大量应用。
TS使开发人员可能把握各种组件的交互方式,并使代码重构变得更加容易;但对于须要精确定义的类型,在应用时会比拟麻烦。特地是波及数个及数十个后端接口数据的类型定义,会有大量的转换和的工夫老本。通过VSCode插件实现一键生成TS申明,能够节俭编程过程的开发成本。
Auto-ts-inline-types简介
为了克服TS的变量类型申明过于繁琐的毛病,节约开发成本,举荐应用VSCode插件【Auto-ts-inline-types】。它能够通过可视化窗口,模仿一个网络申请。通过接口返回的信息,或者手动批改后的信息,主动生成对应的TS申明。
此文章次要介绍插件中Json对象生成TS申明的转换原理。
转换原理
(一)生成所有的interface对象
- 首先对须要转换的Json对象进行遍历,遍历对象所有属性。当遇到属性key/value中的value是object的状况,则开始递归,以此循环。
- 当某个对象遍历后,发现所有属性的value都是根本类型,则生成typeDescription(蕴含HashId和typeObj)。
(备注:HashId为引入第三方包Hash后,通过将typeObj转化为HashId而来,通过HashId保障了typeDescription的唯一性)
// 数据结构示例:
const HashId = 'cc1c310866bbc757b533d7650c9e9934b2e47bf9';
const typeObj = {
name: string;
version: string;
description: string;
main: string;
author: string;
license: string;
}
- 递归开始由内层向外层开始顺次return,最初返回的typeStructure中蕴含rootTypeId和types(蕴含所有生成的typeDescription)。
(备注:如下图所示,在生成的types数组中蕴含所有的interface申明。types中每个元素的的HashId属性用来保护元数据Json对象的层级关系。但在types中,所有对象都是平级的,因为生成的interface都是平级的。在后续的转换过程中,会将HashId替换为变量名,以此生成TS申明)
- 如果发现某个对象的属性中,存在某些value为数组类型,则对数组进行遍历递归。
Value是数组的状况有以下5种:
对于数组的typeDescription构造体如下图所示。【arrayOfTypes】代表该数组中的所有元素类型;【isUnion】代表是下面的表格中,元素类型的第5种状况(多元素类型)。
(二)生成对应Names数组
把接口返回的信息转化为rootTypeId和types组成的对象后,就须要通过HashId和types的对应关系,找到HashId对应的Key,再将Key的首字母变为大写,生成interface中的Name。保护好一份HashId和Name的Json对应关系后,寄存于数组Names中,在转换过程的最初进行替换。
- 首先判断由Json对象转换而来的TypeStructure对象的构造,取出RootTypeId。在types数组中找到RootTypeId对应的typeDescription,遍历typeObj。
- 依据typeObj的数据结构,通过arrayOfTypes来判断是否是数组。
- 如果是数组,则生成对应的类型。
- 如果是对象,则主动生成对象(蕴含HashId与name),放入names数组中。
(三)依据HashId映射生成TS申明
- 通过HashId做映射,将Names数组中的name作为interface的名称。
- 在types数组中,依据HashId寻找每个interface中的属性。如果存在属性的value是HashId的,则在Names中查找对应的name。
- 将生成的interface对象,变换为字符串的模式,蕴含interface以及JSDoc正文。
/**
* @description 结构interface构造体
*/
function getInterfaceStringFromDescription(_a) {
var name = _a.name, typeMap = _a.typeMap;
// 结构interface内部结构
var stringTypeMap = Object.entries(typeMap)
.map(function (_a) {
var key = _a[0], name = _a[1];
return " " + key + ": " + name + ";n";
})
.reduce(function (a, b) { return (a += b); }, "");
// 正文阐明
var descriptionName = `/**n *@description ${name}n`
// 属性类型
var descriptionTypeMap = Object.entries(typeMap)
.map(function (_a) {
var key = _a[0], name = _a[1];
return " *@param {" + name + "} " + key + "n";
})
.reduce(function (a, b) { return (a += b); }, "");
// Doc正文
var descriptionString = descriptionName + descriptionTypeMap + \' */n\'
// 结构interface构造体
var interfaceString = "interface " + name + " {n";
interfaceString += stringTypeMap;
interfaceString += "}";
return descriptionString + interfaceString;
}
(四)生成JSDoc正文
能够在接口返回信息中,间接通过正文来增加每个字段的含意。
- 收集所有的用户手动增加的正文信息,生成正文信息json构造体。
- 在接口的返回信息中,去掉用户的正文,以使返回的文本信息能够转换为Json构造体。
- 在转换的后果中,替换掉曾经正文含意的字段,并写入生成的JSDoc正文中。
/**
* 将中文含意写入JSDoc正文
*/
const getFinalInterface = (text: string) => {
for (let key in commentJson) {
// commentJson是所有的字段和中文含意的对应关系
text = text.replace(key + \'n\', key + \' \' + commentJson[key] + \'n\');
text = text.replace(
key + "\'" + \'n\',
key + "\'" + \' \' + commentJson[key] + \'n\'
);
}
return text;
};
问题总结
- 主动生成的interface对象的程序为递归的程序,json对象的最外层interface(RootType)会被写入生成文件的最上面。目前是手动调整程序,将interface名为RootType的申明置于最顶层,其余字段依照从上到下的顺序排列。
if (name === \'RootObject\') {
// 如果是根对象,则增加至数组头部
nameMap.unshift({ id, name });
} else {
// 如果是其余对象,则在数组前面顺次增加
nameMap.push({ id, name });
}
- 如果在接口返回信息中,存在多个雷同key名的字段,并且用户手动写了不同的含意。目前JSDoc正文会将所有的key名都正文成雷同的含意。
发表回复