这几天开源了一个typescript的json转换工具,使用方式类似于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…