类转换器
叉状通知 —— 说
@dynadok/class-transformer是 Dynadok 维护的叉 类型/类-转换器 (基于v0.5.1). 它扩展已编译的快速路径支持excludeExtraneousValues。 。 。 . 所有原始库的功劳都归TypeStack贡献者(MIT)所有.
它的ES6和Typescript时代. 现在,你的工作 与课堂和建筑对象 比以往任何时候. 类转换器允许您将普通对象转换为某种类,反之亦然. 而且它允许根据标准序列化/去序列化对象. 这个工具在前端和后端都超级有用.
以角 2 为例使用 弹簧。 。 。 . 源代码可用 这里。 。 。 .
目录
- 什么是类转换器
- 安装
- 方法
- 执行类型安全的实例
- 与嵌入对象合作
- 曝光获取器和方法返回值
- 显示不同名称的属性
- 跳过特定属性
- 跳过运行的依赖
- 跳过类中的所有属性
- 跳过私有属性, 或一些前缀属性
- 使用组来控制被排除在外的财产
- 使用版本控制暴露和排除的属性
- 将日期字符串转换为日期对象
- 工作数组
- 其他数据转换
- 其他装饰
- 通用技术
- 隐形类型转换
- 如何处理循环参考?
- 带有角2 的示例
- 样本
- 发布注释
什么是类转换器⬆
在 JavaScript 有两种对象:
- 平方( 升) 对象
- 类(构件)对象
平方物体是指具有下列特性的物体: Object 课.
有时会叫他们 字义 对象,当通过 {} 标注.
类对象是指具有自定义构造器,属性和方法的类.
通常通过 class 标注.
有什么问题吗?
有时你想将普通的 Javascript 对象转换为 ES6 类 没错.
例如,如果你从后端装入一个json, 一些 api 或者从json 文件,
在你后边 JSON.parse 你有一个普通的javascript对象, 而不是你的类.
例如,您在您的用户列表中 users.json 您正在装入 :
[
{
"id": 1,
"firstName": "Johny",
"lastName": "Cage",
"age": 27
},
{
"id": 2,
"firstName": "Ismoil",
"lastName": "Somoni",
"age": 50
},
{
"id": 3,
"firstName": "Luke",
"lastName": "Dacascos",
"age": 12
}
]
你有一个 User 类 :
export class User {
id: number;
firstName: string;
lastName: string;
age: number;
getName() {
return this.firstName + ' ' + this.lastName;
}
isAdult() {
return this.age > 36 && this.age < 60;
}
}
您假设您正在下载类型用户 User 从 users.json 文件并可能想要写入
以下代码:
fetch('users.json').then((users: User[]) => {
// you can use users here, and type hinting also will be available to you,
// but users are not actually instances of User class
// this means that you can't use methods of User class
});
您可以在此代码中使用 users[0].id,也可以使用 users[0].firstName 财务报告和审定财务报表 users[0].lastName。 。 。 .
但是,你无法使用 users[0].getName() 或者说 users[0].isAdult() 因为"用户"其实是
数组普通javascript对象,而不是用户对象的实例.
你居然骗了编译员 你说它的 users: User[]。 。 。 .
那怎么办? 怎样做一个 users 实例 User 对象而不是普通的 javascript 对象?
解决方案是创建用户对象的新实例并手动将所有属性复制到新对象.
但是一旦你有了更复杂的对象等级,事情可能会很快发生错误.
替代品? 是的,你可以使用类转换器。 这个图书馆的用意是帮助您绘制您的普通的javascript 对象为您所选的类.
这个库对于在你的API中曝光的模型也非常出色, 因为它提供了很好的工具 控制你的模型 正在你的API. 下面是一个例子,它将是什么样子:
fetch('users.json').then((users: Object[]) => {
const realUsers = plainToClass(User, users);
// now each user in realUsers is an instance of User class
});
现在你可以用 users[0].getName() 财务报告和审定财务报表 users[0].isAdult() 方法。 。 .
安装⬆
节点.js⬆
-
安装模块 :
npm install class-transformer --save -
reflect-metadatashim 需要, 安装它:npm install reflect-metadata --save并且确保将它导入到一个全球性的地方,比如应用:
import 'reflect-metadata'; -
使用ES6特性,如果您使用旧版本的节点.js,您可能需要安装es6-shim:
npm install es6-shim --save并导入到一个全球性的地方, 如 app. ts :
import 'es6-shim';
浏览器⬆
-
安装模块 :
npm install class-transformer --save -
reflect-metadatashim 需要, 安装它:npm install reflect-metadata --save添加
<script>在您头部反射-元数据index.html数字 :<html> <head> <!-- ... --> <script src="node_modules/reflect-metadata/Reflect.js"></script> </head> <!-- ... --> </html>如果你使用角2,你应该已经安装了这个shim.
-
如果您正在使用系统.js, 您可能想要将此添加到
map财务报告和审定财务报表package配置 :{ "map": { "class-transformer": "node_modules/class-transformer" }, "packages": { "class-transformer": { "main": "index.js", "defaultExtension": "js" } } }
方法⬆
普通类⬆
这种方法将普通的javascript对象转换为特定类的实例.
import { plainToClass } from 'class-transformer';
let users = plainToClass(User, userJson); // to convert user plain object a single user. also supports arrays
plain Toclass FromExist 软件⬆
这种方法将普通对象转换成实例,使用一个已经填充的对象,这是目标类的一个实例.
const defaultUser = new User();
defaultUser.role = 'user';
let mixedUser = plainToClassFromExist(defaultUser, user); // mixed user should have the value role = user when no value is set otherwise.
类待处理⬆
这种方法将您的类对象转换回普通的 Javascript 对象, 可以是 JSON.stringify 等会.
import { classToPlain } from 'class-transformer';
let photo = classToPlain(photo);
类分类⬆
此方法将您的类对象转换为类对象的新实例 . 这可能会被当作你的物体的深克隆.
import { classToClass } from 'class-transformer';
let photo = classToClass(photo);
您也可以使用一个 ignoreDecorators 选项在变换选项中忽略您所使用所有装饰.
序列化⬆
您可以使用 serialize 方法 :
import { serialize } from 'class-transformer';
let photo = serialize(photo);
serialize 与数组和非数组同时工作.
拆除和拆除箭头⬆
你可以用Json的 deserialize 方法 :
import { deserialize } from 'class-transformer';
let photo = deserialize(Photo, photo);
使去区域化与数组配合,使用 deserializeArray 方法 :
import { deserializeArray } from 'class-transformer';
let photos = deserializeArray(Photo, photos);
执行类型安全的实例⬆
默认行为 plainToClass 方法是设置 全部 纯对象属性,
甚至是班级上没有规定的.
import { plainToClass } from 'class-transformer';
class User {
id: number;
firstName: string;
lastName: string;
}
const fromPlainUser = {
unkownProp: 'hello there',
firstName: 'Umed',
lastName: 'Khudoiberdiev',
};
console.log(plainToClass(User, fromPlainUser));
// User {
// unkownProp: 'hello there',
// firstName: 'Umed',
// lastName: 'Khudoiberdiev',
// }
如果这种行为不适合你的需要,你可以使用 excludeExtraneousValues 选项
输入 plainToClass 方法时 显示所有类属性 作为一项要求.
import { Expose, plainToClass } from 'class-transformer';
class User {
@Expose() id: number;
@Expose() firstName: string;
@Expose() lastName: string;
}
const fromPlainUser = {
unkownProp: 'hello there',
firstName: 'Umed',
lastName: 'Khudoiberdiev',
};
console.log(plainToClass(User, fromPlainUser, { excludeExtraneousValues: true }));
// User {
// id: undefined,
// firstName: 'Umed',
// lastName: 'Khudoiberdiev'
// }
与嵌入对象合作⬆
当你试图改变 已经嵌入物体的物体,
它需要知道你想要改变的物体类型.
由于Typescript还没有很好的反射能力,
我们应该隐含地说明每个财产包含的物体类型.
使用 @Type 装饰师.
假设我们有一张带相片的相册. 我们正在尝试将相册普通对象转换为类对象:
import { Type, plainToClass } from 'class-transformer';
export class Album {
id: number;
name: string;
@Type(() => Photo)
photos: Photo[];
}
export class Photo {
id: number;
filename: string;
}
let album = plainToClass(Album, albumJson);
// now album is Album object with Photo objects inside
提供多个类型选项⬆
如果被嵌入对象可以是不同类型,您可以提供额外的选项对象,
规定歧视者。 歧视者选项必须界定 property 带有子类型
对象的名称和可能 subTypes 被嵌入对象可以转换为。 子类型
有一个 value中,该类型和 name,可以与 property
歧视者.
假设我们有一张专辑 有一张顶级相片。 但是,这张照片可以是某些不同类型的.
我们正在尝试将相册平面对象转换成类对象。 普通对象输入必须定义
额外财产 __type。该属性在转换过程中默认删除 :
JSON 输入数字 :
{
"id": 1,
"name": "foo",
"topPhoto": {
"id": 9,
"filename": "cool_wale.jpg",
"depth": 1245,
"__type": "underwater"
}
}
import { Type, plainToClass } from 'class-transformer';
export abstract class Photo {
id: number;
filename: string;
}
export class Landscape extends Photo {
panorama: boolean;
}
export class Portrait extends Photo {
person: Person;
}
export class UnderWater extends Photo {
depth: number;
}
export class Album {
id: number;
name: string;
@Type(() => Photo, {
discriminator: {
property: '__type',
subTypes: [
{ value: Landscape, name: 'landscape' },
{ value: Portrait, name: 'portrait' },
{ value: UnderWater, name: 'underwater' },
],
},
})
topPhoto: Landscape | Portrait | UnderWater;
}
let album = plainToClass(Album, albumJson);
// now album is Album object with a UnderWater object without `__type` property.
提示:同样适用于具有不同子类型的数组. 此外,你可以说明 keepDiscriminatorProperty: true
在选项中将歧视者的财产也保留在相应的类别中.
曝光获取器和方法返回值⬆
您可以通过设置 @Expose() 这些获取器或方法的装饰器:
import { Expose } from 'class-transformer';
export class User {
id: number;
firstName: string;
lastName: string;
password: string;
@Expose()
get name() {
return this.firstName + ' ' + this.lastName;
}
@Expose()
getFullName() {
return this.firstName + ' ' + this.lastName;
}
}
显示不同名称的属性⬆
如果你想揭露一些有不同名称的属性,
您可以通过指定 name 选项到 @Expose 装饰 :
import { Expose } from 'class-transformer';
export class User {
@Expose({ name: 'uid' })
id: number;
firstName: string;
lastName: string;
@Expose({ name: 'secretKey' })
password: string;
@Expose({ name: 'fullName' })
getFullName() {
return this.firstName + ' ' + this.lastName;
}
}
跳过特定属性⬆
有时您想要在转换时跳过一些属性 .
可用 @Exclude 装饰 :
import { Exclude } from 'class-transformer';
export class User {
id: number;
email: string;
@Exclude()
password: string;
}
当你改变一个用户时 password 属性将被跳过而不包含在已改变的结果中.
跳过运行的依赖⬆
您可以控制您要排除财产的操作 。 使用 toClassOnly 或者说 toPlainOnly 选项:
import { Exclude } from 'class-transformer';
export class User {
id: number;
email: string;
@Exclude({ toPlainOnly: true })
password: string;
}
现在 password 财产仅在 classToPlain 操作。 反之亦然,请使用 toClassOnly 选项.
跳过类中的所有属性⬆
您可以跳过该类的所有属性, 并只披露那些是明确需要的:
import { Exclude, Expose } from 'class-transformer';
@Exclude()
export class User {
@Expose()
id: number;
@Expose()
email: string;
password: string;
}
现在 id 财务报告和审定财务报表 email 将打开,在转换时将排除密码.
或者,您可以在转型期间设定排斥策略:
import { classToPlain } from 'class-transformer';
let photo = classToPlain(photo, { strategy: 'excludeAll' });
在这种情况下,你不需要 @Exclude() 整个班级.
跳过私有属性, 或一些前缀属性⬆
如果您用前缀命名您的私有属性, 请用 _, (中文(简体) ),
然后,您也可以将此类属性排除在转换之外:
import { classToPlain } from 'class-transformer';
let photo = classToPlain(photo, { excludePrefixes: ['_'] });
这将跳过开始的所有属性 _ 前缀.
您可以通过任意数量的前缀,所有从这些前缀开始的属性都会被忽略.
例如:
import { Expose, classToPlain } from 'class-transformer';
export class User {
id: number;
private _firstName: string;
private _lastName: string;
_password: string;
setName(firstName: string, lastName: string) {
this._firstName = firstName;
this._lastName = lastName;
}
@Expose()
get name() {
return this._firstName + ' ' + this._lastName;
}
}
const user = new User();
user.id = 1;
user.setName('Johny', 'Cage');
user._password = '123';
const plainUser = classToPlain(user, { excludePrefixes: ['_'] });
// here plainUser will be equal to
// { id: 1, name: "Johny Cage" }
使用组来控制被排除在外的财产⬆
您可以使用组来控制哪些数据将会被曝光,哪些不会被曝光 :
import { Exclude, Expose, classToPlain } from 'class-transformer';
export class User {
id: number;
name: string;
@Expose({ groups: ['user', 'admin'] }) // this means that this data will be exposed only to users and admins
email: string;
@Expose({ groups: ['user'] }) // this means that this data will be exposed only to users
password: string;
}
let user1 = classToPlain(user, { groups: ['user'] }); // will contain id, name, email and password
let user2 = classToPlain(user, { groups: ['admin'] }); // will contain id, name and email
使用版本控制暴露和排除的属性⬆
如果您正在构建一个具有不同版本的API,类转换器对此有极其有用的工具. 您可以控制在哪个版本中显示或排除您的模型的哪些属性 。 示例
import { Exclude, Expose, classToPlain } from 'class-transformer';
export class User {
id: number;
name: string;
@Expose({ since: 0.7, until: 1 }) // this means that this property will be exposed for version starting from 0.7 until 1
email: string;
@Expose({ since: 2.1 }) // this means that this property will be exposed for version starting from 2.1
password: string;
}
let user1 = classToPlain(user, { version: 0.5 }); // will contain id and name
let user2 = classToPlain(user, { version: 0.7 }); // will contain id, name and email
let user3 = classToPlain(user, { version: 1 }); // will contain id and name
let user4 = classToPlain(user, { version: 2 }); // will contain id and name
let user5 = classToPlain(user, { version: 2.1 }); // will contain id, name and password
将日期字符串转换为日期对象⬆
有时,您在普通的javascript对象中有一个以字符串格式接收的日期.
您想要从中创建一个真正的 Javascript Date 对象 .
您可以简单地将日期对象传递到 @Type 装饰 :
import { Type } from 'class-transformer';
export class User {
id: number;
email: string;
password: string;
@Type(() => Date)
registrationDate: Date;
}
同样的技术可以使用 Number, (中文(简体) ), String, (中文(简体) ), Boolean
当您想要将您的值转换为这些类型时, 原始类型 .
工作数组⬆
当您使用数组时,您必须提供数组所包含对象的类型.
此类型,请在 @Type() 装饰 :
import { Type } from 'class-transformer';
export class Photo {
id: number;
name: string;
@Type(() => Album)
albums: Album[];
}
您也可以使用自定义的数组类型 :
import { Type } from 'class-transformer';
export class AlbumCollection extends Array<Album> {
// custom array functions ...
}
export class Photo {
id: number;
name: string;
@Type(() => Album)
albums: AlbumCollection;
}
图书馆将自动处理适当的转换.
ES6号集 Set 财务报告和审定财务报表 Map 还要求 @Type 装饰 :
export class Skill {
name: string;
}
export class Weapon {
name: string;
range: number;
}
export class Player {
name: string;
@Type(() => Skill)
skills: Set<Skill>;
@Type(() => Weapon)
weapons: Map<string, Weapon>;
}
其他数据转换⬆
基本用途⬆
您可以使用 @Transform 装饰师.
例如,你想让自己的 Date 对象为 a moment 当您是对象时
将对象从平面转换成类 :
import { Transform } from 'class-transformer';
import * as moment from 'moment';
import { Moment } from 'moment';
export class Photo {
id: number;
@Type(() => Date)
@Transform(({ value }) => moment(value), { toClassOnly: true })
date: Moment;
}
现在当你打电话 plainToClass 并派遣一个明亮的、,
它将把相片对象中的日期值转换为瞬间日期.
@Transform 装饰者还支持组和版本.
高级用途⬆
这个 @Transform 给装饰者提供了更多的参数,以便您配置您想要如何完成转换 .
@Transform(({ value, key, obj, type }) => value)
| 参数 | 说明 |
|---|---|
value | 变相前的财产价值. |
key | 被改造后的财产名称. |
obj | 变相源对象. |
type | 变相类型. |
options | 选项对象传递到转换方法. |
其他装饰⬆
| 签署 | 示例 | 说明 |
|---|---|---|
@TransformClassToPlain | @TransformClassToPlain({ groups: ["user"] }) | 用类"ToPlain"来转换方法返回并曝光类中的属性. |
@TransformClassToClass | @TransformClassToClass({ groups: ["user"] }) | 以类ToClass来转换方法返回并曝光类中的属性. |
@TransformPlainToClass | @TransformPlainToClass(User, { groups: ["user"] }) | 用平原ToClass来转换方法返回,并曝光类中的属性. |
上述装饰者接受一个任择论点: Class Transform 选项 - 组,版本,名称等变换选项
一个例子是:
@Exclude()
class User {
id: number;
@Expose()
firstName: string;
@Expose()
lastName: string;
@Expose({ groups: ['user.email'] })
email: string;
password: string;
}
class UserController {
@TransformClassToPlain({ groups: ['user.email'] })
getUser() {
const user = new User();
user.firstName = 'Snir';
user.lastName = 'Segal';
user.password = 'imnosuperman';
return user;
}
}
const controller = new UserController();
const user = controller.getUser();
页:1 user 变量只包含第一个Name, lastName, 电子邮件属性, 因为它们是
被曝光的变量。 电子邮件属性也暴露了,因为我们对组"用户. email"进行了感动.
通用技术⬆
通用不支持, 因为 TypeScript 还没有很好的反射能力 . 一旦TypeScript团队为我们提供了更好的运行时间类型反射工具,将实施通用. 有一些微软,无论你可以用, 也许可以解决你的问题. 检查这个例子 .
隐形类型转换⬆
页:1 如果您同时使用类验证器和类转换器, 您可能不会启用此功能 .
根据Typescript提供的类型信息,允许内置类型之间的自动转换. 默认禁用 .
import { IsString } from 'class-validator';
class MyPayload {
@IsString()
prop: string;
}
const result1 = plainToClass(MyPayload, { prop: 1234 }, { enableImplicitConversion: true });
const result2 = plainToClass(MyPayload, { prop: 1234 }, { enableImplicitConversion: false });
/**
* result1 will be `{ prop: "1234" }` - notice how the prop value has been converted to string.
* result2 will be `{ prop: 1234 }` - default behaviour
*/
如何处理循环参考?⬆
循环引用被忽略.
比如说,如果你在改变阶级 User 包含属性 photos 类型 Photo, (中文(简体) ),
财务报告和审定财务报表 Photo 包含链接 user 发送给其父母 User,则 user 将在转换时被忽略.
循环引用不仅仅在 classToClass 操作.
带有角2 的示例⬆
假设您想要下载用户, 希望自动将其映射到 User 课.
import { plainToClass } from 'class-transformer';
this.http
.get('users.json')
.map(res => res.json())
.map(res => plainToClass(User, res as Object[]))
.subscribe(users => {
// now "users" is type of User[] and each user has getName() and isAdult() methods available
console.log(users);
});
您也可以输入一个类 ClassTransformer 作为服务于 providers,并使用其方法.
以角 2 为例使用 弹簧。 。 。 . 源代码为 这里。 。 。 .
样本⬆
看看里面的样本 ./样本 更多实例 诸用相.
发布注释⬆
参见关于突破更改和发布注释的信息 这里。 。 。 .