JSON object conversion TypeScript type implementation logic

To be honest, you just want to be simple and practical, and you can convert it on this website: Simple and convenient online JSON to typescript tool - ToolTT online toolbox

 

TypeScript (TS) is a strongly typed programming language, which is widely used by front-end teams because problems in the code can be found at compile time.

TS enables developers to grasp the interaction of various components and makes code refactoring easier; but for types that need to be accurately defined, it will be more troublesome to use. Especially for type definitions involving several or dozens of back-end interface data, there will be a lot of conversion and time costs. One-click generation of TS declarations through the VSCode plug-in can save development costs in the programming process.

Introduction to Auto-ts-inline-types

In order to overcome the cumbersome shortcomings of TS variable type declarations and save development costs, it is recommended to use the VSCode plug-in [Auto-ts-inline-types]. It can simulate a network request through the visualization window. The corresponding TS statement is automatically generated through the information returned by the interface or the manually modified information.

This article mainly introduces the conversion principle of TS statement generated from Json object in the plug-in.

Conversion principle

(1) Generate all interface objects

  1. First, traverse the Json object that needs to be converted, and traverse all the properties of the object. When the value in the attribute key/value is an object, it starts recursive and loops.
  2. When an object is traversed and it is found that the values ​​of all attributes are basic types, typeDescription (including HashId and typeObj) is generated.
    (Remarks: HashId is obtained by converting typeObj into HashId after introducing the third-party package Hash, and the uniqueness of typeDescription is guaranteed through HashId)
// 数据结构示例:
const HashId = 'cc1c310866bbc757b533d7650c9e9934b2e47bf9';
const typeObj = {
  name: string;
  version: string;
  description: string;
  main: string;
  author: string;
  license: string;
}
  1. The recursion starts from the inner layer to the outer layer and returns sequentially, and the typeStructure returned finally contains rootTypeId and types (including all generated typeDescriptions).

(Note: As shown in the figure below, all interface declarations are included in the generated types array. The HashId attribute of each element in types is used to maintain the hierarchical relationship of metadata Json objects. But in types, all objects are flat Level, because the generated interfaces are all flat. In the subsequent conversion process, the HashId will be replaced with the variable name to generate the TS statement)

  1. If it is found that some values ​​in the properties of an object are array types, the array is recursively traversed.

There are five cases where Value is an array:

The typeDescription structure for the array is shown in the figure below. [arrayOfTypes] represents all element types in the array; [isUnion] represents the fifth case of the element type (multi-element type) in the above table.

(2) Generate the corresponding Names array

After converting the information returned by the interface into an object composed of rootTypeId and types, you need to find the Key corresponding to the HashId through the correspondence between HashId and types, and then change the first letter of the Key to uppercase to generate the Name in the interface. After maintaining a Json correspondence between HashId and Name, store it in the Names array and replace it at the end of the conversion process.

  1. First judge the structure of the TypeStructure object converted from the Json object, and take out the RootTypeId. Find the typeDescription corresponding to RootTypeId in the types array, and traverse typeObj.
  2. According to the data structure of typeObj, whether it is an array is judged by arrayOfTypes.
  3. If it is an array, generate the corresponding type.
  4. If it is an object, the object (including HashId and name) is automatically generated and put into the names array.

(3) Generate TS statement according to HashId mapping

  1. Use HashId for mapping, and use the name in the Names array as the name of the interface.
  2. In the types array, look for attributes in each interface according to the HashId. If the value of the existing attribute is HashId, the corresponding name is searched in Names.
  3. Transform the generated interface object into a string, including interface and JSDoc comments.
/**
 * @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;
}

(4) Generate JSDoc comments

The meaning of each field can be added directly through annotations in the interface return information.

  1. Collect all the annotation information manually added by the user, and generate the annotation information json structure.
  2. In the return information of the interface, remove the user's comments so that the returned text information can be converted into a Json structure.

  1. In the converted result, replace the field with commented meaning and write it into the generated JSDoc comment.

/**
 * 将中文含义写入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;
};

 

conclusion of issue

  1. The order of automatically generated interface objects is a recursive order, and the outermost interface (RootType) of the json object will be written at the bottom of the generated file. At present, the order is manually adjusted, and the declaration of the interface named RootType is placed at the top level, and the rest of the fields are arranged in order from top to bottom.
if (name === \'RootObject\') {
    // 如果是根对象,则添加至数组头部
    nameMap.unshift({ id, name });
} else {
    // 如果是其他对象,则在数组后面依次添加
    nameMap.push({ id, name });
}
  1. If there are multiple fields with the same key name in the information returned by the interface, and the user manually writes different meanings. Currently, JSDoc comments annotate all key names with the same meaning.

Guess you like

Origin blog.csdn.net/weixin_44786530/article/details/130085192