
Security News
The Hidden Blast Radius of the Axios Compromise
The Axios compromise shows how time-dependent dependency resolution makes exposure harder to detect and contain.
json-mapper-class
Advanced tools
json-mapper-class 是类似flutter Json序列化的 web前端 优雅 解决方案,用来将接口 json 数据映射到 class 的工具,之后在我们的TypeScript项目中,可以通过 类来为接口返回数据标注类型,通过修改类属性达到不需要后端修改接口数据字段的情况下,前端来任意定义接口返回字段的效果,解决了实际项目中接口数据与页面深度耦合的过程,并提供其逆过程。
json-mapper-class 是一个独立的插件,可以与任何的 TypeScript 项目进行深度的集成(最好是class语法),同时提供了众多的装饰器,让你更加优雅的去编写 TypeScript,请仔细阅读文档。
同时为了方便 json-mapper-class 的方法 toClass 第二个参数的生成,也是为了避免手动编写json-mapper-class 标准类 模版代码 的过程,本人开发第二个插件简化了过程,插件地址(请自信阅读文档):
下面是一个案例:
import { property, toClass } from 'json-mapper-class';
class UserModel {
@property('i')
id: number;
@property()
name: string;
}
const userRaw = {
i: 1234,
name: 'name',
};
// 使用 toClass 将 json 转换成 class
const userModel = toClass(userRaw, UserModel);
// 你将获得如下数据
{
id: 1234,
name: 'name',
}
npm i json-mapper-class --save
如果你想转换一个聚合对象,需要提供目标类。如果该对象的某个属性值是数组,则会递归该数组的所有元素(不管层级有多深),自动转换为目标类的实例。
列子:
class NestedModel {
@property('e', UserModel)
employees: UserModel[];
@typed(UserModel)
@property('u')
user: UserModel;
}
const model = toClass(
{
e: [
{ i: 1, n: 'n1' },
{ i: 2, n: 'n2' },
],
u: {
i: 1,
n: 'name',
}
},
NestedModel,
);
// you will get like this
{
employees: [
{ id: 1, name: 'n1' },
{ id: 2, name: 'n2' },
],
user: {
id: 1,
name: 'name'
}
}
const model = toPlain(
{
employees: [
{ id: 1, name: 'n1' },
{ id: 2, name: 'n2' },
],
user: {
id: 1,
name: 'name'
}
},
NestedModel,
);
// you will get like this
{
e: [
{ i: 1, n: 'n1' },
{ i: 2, n: 'n2' },
],
u: {
i: 1,
n: 'name'
}
}
import * as moment from 'moment';
export class EduModel {
@property('i')
id: number;
@property('crt')
@deserialize(value => moment(value).format('YYYY-MM-DD HH:mm:ss'))
createTime: string;
}
class EmailModel {
@property('s')
site: string;
@property('e')
@deserialize((value, _instance, origin) => `${value}@${origin.s}`)
email: string;
}
将一个 json 对象映射成一个类实例
raw / raws <Object|Array<Object>> 一个 josn 对象或者 json 对象数据clazzType <Class> 类的构造函数options? <Object> 配置
ignoreDeserializer <Boolean> 当设置为 true 时,不会调用使用 @deserialize 装饰器配置的方法ignoreBeforeDeserializer <Boolean> 当设置为 true 时,不会调用使用 @beforeDeserialize 装饰器配置的方法distinguishNullAndUndefined <Boolean> 当设置为 true 时,区分 null 和 undefined示例:
const userRaw = {
i: 1234,
name: 'name',
};
const userRaws = [
{
i: 1000,
name: 'name1',
},
{
i: 2000,
name: 'name2',
},
];
const userModel = toClass(userRaw, UserModel);
const userModels = toClasses(userRaws, UserModel);
将一个类实例或者 json 对象映射成另外一个 json 对象
instance / instances <Object|Array<Object>> 一个 json 或类实例,或者一个json或类实例组成的数组clazzType <Class> Constructor of the target classoptions? <Object> 类的构造函数
ignoreSerializer <Boolean> 当设置为 true 时,不会调用使用 @serialize 装饰器配置的方法ignoreAfterSerializer <Boolean> 当设置为 true 时,不会调用使用 @afterSerialize 装饰器配置的方法distinguishNullAndUndefined <Boolean> 当设置为 true 时,区分 null 和 undefined示例:
const userModel = {
id: 1234,
name: 'name',
};
const userModels = [
{
id: 1000,
name: 'name1',
},
{
id: 2000,
name: 'name2',
},
];
const userRaw = toPlain(userModel, UserModel);
const userRaws = toPlains(userModels, UserModel);
调用不同的方法时,这些装饰器的执行顺序:
toClass/toClasses: beforeDeserializer => typed(映射成一个类实例) => deserializertoPlain/toPlains: serializer => typed(映射成一个对象) => afterSerializer将一个 key 映射到另外一个 key,如 n => name
originalKey <string> 被映射的数据 key, 如果不传则默认同名clazzType <Class> 自动将该属性的值映射到一个类实例,相当于调用了 toClass 方法optional <Boolean> 是否可选示例:
class PropertyModel {
@property('i')
id: number;
@property()
name: string;
@property('u', UserModel)
user: UserModel;
@property('t', null, true)
timeStamp: number;
}
const model = toClass({ i: 234, name: 'property', u: { i: 123, n: 'name' } }, PropertyModel);
// 你将获得如下数据
{
id: 234,
name: 'property',
user: {
id: 123,
name: 'name'
}
}
设置一个目标类的构造器,相当于 property 装饰器的第二个参数
clazzType <Class> 自动将该属性的值映射到一个类实例,相当于调用了 toClass 方法示例:
// 与此设置一致 @property('n', UserModel)
class TypedModel {
@typed(UserModel)
@property('u')
user: UserModel;
}
const model = toClass({ u: { i: 123, n: 'name' } }, TypedModel);
// 你将获得如下数据
{
user: {
id: 123,
name: 'name'
}
}
设置一个属性为可选,相当于 property 装饰器的第三个参数
示例:
// 与此设置一致 @property('n', null, true)
class OptionalModel {
@optional()
@property('n')
name: string;
}
const model = toClass({}, OptionalModel);
// 你将获得如下数据
{
}
const model = toClass({ n: 'name' }, OptionalModel);
// 你将获得如下数据
{
name: 'name';
}
给当前属性设置默认值
val <Any> 要设置的默认值示例:
class DefaultValModel {
@defaultVal(0)
@property('i')
id: number;
}
const model = toClass({}, DefaultValModel);
// 你将获得如下数据
{
id: 0;
}
const raw = toPLain({}, DefaultValModel);
// 你将获得如下数据
{
i: 0;
}
当调 toPlain 进行序列化时,用使用当前数据作为基准
示例:
class SerializeTargetModel {
@serializeTarget()
@property('n')
name: string;
@property('n')
nick: string;
}
const raw = toPlain(
{
name: 'name',
nick: 'nick',
},
SerializeTargetModel,
);
// 你将获得如下数据
{
n: 'name';
}
在 @typed 调用之前调用
beforeDeserializer <(value: any, instance: any, origin: any) => any>
value <Any> 该属性在原始对象中的值instance <Instance> 类实例(未完成解析)origin <Object> 原始对象disallowIgnoreBeforeDeserializer <Boolean> 默认为 false,如果设置为 true,则当调用 toClass 时,将强制调用 @beforeDeserialize 配置的方法示例:
class BeforeDeserializeModel {
@beforeDeserialize((value: any) => JSON.parse(value))
@property('m')
mail: object;
}
toClass(
{
m: '{"id":123}',
},
BeforeDeserializeModel,
);
// 你将获得如下数据
{
mail: { id: 123 },
};
将原始对象序列化成自定义的数组格式,仅在调用 toClass/toClasses 时可用
deserializer (value: any, instance: any, origin: any) => any
value <Any> 该属性的值经过 @beforeDeserialize 和 @typed 调用后的结果instance <Instance> 类实例(未完成解析)origin <Object> A raw objectdisallowIgnoreDeserializer <Boolean> 默认为 false,如果设置为 true,则当调用 toClass 时,将强制调用 @deserialize 配置的方法示例:
class DeserializeModel {
@deserialize((value: string) => `${value}@xxx.com`)
@property('m')
mail: string;
}
toClass(
{
m: 'mail',
},
DeserializeModel,
);
// 你将获得如下数据
{
mail: 'mail@xxx.com',
};
自定义属性值的序列化方式,仅当调用 toPlain/toPlains 时可用
serializer (value: any, instance: any, origin: any) => any
value <Any> 该属性在类实例中的值instance <Instance> 当前类实例origin <Object> 一个json对象(未完成序列化)disallowIgnoreSerializer <Boolean> 默认为 false,如果设置为 true,则当调用 toClass 时,将强制调用 @serialize 配置的方法Example:
class SerializeModel {
@serialize((mail: string) => mail.replace('@xxx.com', ''))
@property('e')
mail: string;
}
toPlain(
{
mail: 'mail@xxx.com',
},
SerializeModel,
);
// 你将获得如下数据
{
e: 'mail@xxx.com',
}
Convert a key/value in instance to a target form data, it happened after serializer only
afterSerializer (value: any, instance: any, origin: any) => any
value <Any> 该属性的值经过 @serializer 和 @typed 调用后的结果instance <Instance> 当前类实例origin <Object> 一个json对象(未完成序列化)disallowIgnoreAfterSerializer <Boolean> 默认为 false,如果设置为 true,则当调用 toClass 时,将强制调用 @afterSerialize 配置的方法示例:
class AfterSerializeModel {
@afterSerialize((mail: string) => JSON.stringify(mail))
@property('e')
mail: string;
}
toPlain(
{
mail: { id: 1000 },
},
SerializeModel,
);
// 你将获得如下数据
{
e: '{"id":1000}',
};
FAQs
Json Mapper To Class
We found that json-mapper-class demonstrated a not healthy version release cadence and project activity because the last version was released a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Security News
The Axios compromise shows how time-dependent dependency resolution makes exposure harder to detect and contain.

Research
A supply chain attack on Axios introduced a malicious dependency, plain-crypto-js@4.2.1, published minutes earlier and absent from the project’s GitHub releases.

Research
Malicious versions of the Telnyx Python SDK on PyPI delivered credential-stealing malware via a multi-stage supply chain attack.