开源了个工具,通过TS装饰器来转换JSON

399 阅读4分钟

json2ts.png

这几天开源了一个typescriptjson转换工具,使用方式类似于Android中的gson,写个文章记录下。

起因如下:

  • 后台的返回数据名不是很友好,定义了不同的字段名来描述了同一个字段
  • 后台返回的数据命名是下划线分隔的形式,前端想要驼峰,类型定义命名被后台的数据牵着鼻子走。
  • 请求后台接口后,返回的数据并不是一个Class Object,也就是无法直接调用方法等,外部使用class-transformer转换的话容易出纰漏,造成有的是plain Object有的是Class object
  • 项目中数据类型定义、使用无法规范
  • ...

工具功能如下:

  • 可以通过注解实现将不同的字段名转换为统一名称
  • 可以设置字段转换类型
  • 支持数组的类型转换
  • 支持数据转换后的统一处理
  • 支持数据转换前的统一处理
  • 支持类型设置继承关系
  • 可以自定义方法继承原有注解
  • 可以配置axios 实现后台数据返回后的统一转换
  • ...

实现原理:

  • 主要通过JSON.parse()第二个参数进行数据处理
  • 通过ts装饰器来获取转换规则
  • ...

开源地址:

github:github.com/AlwaysSum/j… npm:www.npmjs.com/package/jso…

json-transform-Utils

A tool for converting json's field names in typescript or javascript! Support multiple individual names!

一个用于转换 json 字段名的 ts/js 工具,支持多个别名

1、 普通使用

安装

 npm install json-transform-utils

普通对象转换

例 1:通过对象转换,以下例子会所有对应的 key 为a的转换为 key 为params1

import { JSONParse } from "json-transform-utils";

const data = "{a:1,b:2,c:{a:2,b:3}}";
JSONParse(data, { a: "params1" });

//结果为  "{params1:1,b:2,c:{params1:2,b:3}}"

通过注解转换

例子 2:通过对象注解转换

需注意声明顺序,比如以下场景中,City 应该声明在 Person 前面。

export class City {
  id: string;
  @JsonField({ names: ["city_name", "cityName"] })
  name: string;
}

export class Dog {
  @JsonField("dog_name")
  name: string;
}

export class Cat {
  @JsonField("cat_name")
  name: string;
}

export class Pet {
  @JsonField({ names: ["pets_dogs"], from: Dog })
  dogs: Dog[];
  @JsonField({ names: ["pets_cats"], from: Cat })
  cats: Cat[];
}

export class Person {
  id: string;
  @JsonField("person_name")
  name: string;
  @JsonField({ names: ["person_age", "old_person_age"] })
  age: number;
  @JsonField({ names: ["city"], from: City })
  city: City;

  @JsonField({ from: Pet })
  pets: Pet[];
}

//--处理单个对象
const data = "<person的对象json字符串>";
JSONParse(data, Person);

//--处理嵌套数据:例如分页
const data = "{page:1,total_page:100,contents:<person的对象json字符串>}";
JSONParse(data, { contents: Person });

转换监听

工具提供了一个 class 注解,通过该注解,可以处理转换前的数据类型 和转换后的数据。

简单示例:

@JSONClass({
    after:(result, parse: TransformParseObject, json: string)=>{
       result.customData = "示范修改数据"
       return result
    }
})
 export class YourRespose{
    @JsonField('name')
    name: string
    
    customData:string
 }

示例一:

通过,定义全局的转换方法,配合class-transformer实现请求后直接将 plain object 转换为 class object 。

/**
 * 一些普通的转换为Class的方法
 * Some common ways to convert to Class
 * @returns
 */
export function CommonJSONClass() {
  return JSONClass({
    after: function (result: BlockResInfo, parse: TransformParseObject, json: string) {
      if (typeof parse === "function") {
        return plainToInstance(parse, result);
      } else {
        return result;
      }
    },
  });
}

/**
 * 使用注解
 */
@CommonJSONClass()
export class YouerRespose {
    @JsonField('name')
    name: string
}

示例二:

通过JSONClass()注解实现带继承关系的类型转换和转换前的数据处理



/**
 * BlockResInfo的一些特殊解析处理
 * @returns
 */
export function MyJSONClass() {
    return JSONClass({
        /**
        * 转换后可以完善一些数据
        */
        after: function (
            result: BlockResInfo,
            parse: TransformParseObject,
            json: string
        ) {
            //示范:字段数据完善,或改造
            if (!result.type) result.type = 'father'

            if (typeof parse === 'function') {
                 //这里的parse是转换类型,转换为对应的 class object
                return plainToInstance(parse, result)
            } else {
                return plainToInstance(Father, result)
            }
        },
        /**
        *通过数据判断应该转换为什么子类型
        */
        beforeParse: function (data: any, parse, json: string) {
            let type = Father
            if ('child_one_name' in data) {
                type = ChildOne
            }else if('child_two_name' in data){
                type = ChildTwo
            }
            return type
        }
    })
}



@MyJSONClass()
export class Father {
    @JsonField('name')
    name: string
    @JsonField('type')
    type: 'child_one'|'child_two'|'father'
}

@MyJSONClass()
export class ChildOne extends Father{
    @JsonField('child_one_name')
    childName: string
}

@MyJSONClass()
export class ChildTwo extends Father{
    @JsonField('child_two_name')
    childName: string
}



和 Axios 框架配合使用

1、步骤一:扩展 Axios 的配置参数

import { TransformParseObject } from "json-transform-utils";
//---扩展属性
declare module "axios" {
  export interface AxiosRequestConfig {
    transformJson?: TransformParseObject; // 转换为json的映射属性
  }
}

2、步骤二: 新增transformResponse转换属性:

const axios = axiosClient.create({
  //<...其他参数>
  transformResponse: [
    function (this: AxiosRequestConfig, data: string, headers: any) {
      /**
       * Some other processing can be done here.For example, with the *`class-transform` dependency library, you can convert `plain Object` to *`Class Object`.
       *
       * 在这里可以进行一些其他的处理
       * 例如利用class-transformer 依赖库,可以将plain Object 转换为 Class Object
       */
      return JSONParse(data, this.transformJson);
    },
  ],
});

3、步骤三:请求数据

//Post
axios.post<ResposeInfo>(
  "youer request url",
  { params: 1 },
  {
    // 设置转换方法
    transformJson: PlatformResInfo,
  }
);

//Get
axios.get<PageInfo<ResposeInfo>>("youer request url", {
  params: {
    page: params.page ?? 1, //页码
  },
  transformJson: {
    contents: ResposeInfo,
  },
});

PS: 可以利用 class-transformer 依赖库配合将 plain Object 转换为 Class Object

类型转换工具:class-transformer npm:www.npmjs.com/package/cla…

Thinks ~