class-transformer
Its ES6 and Typescript era. Nowadays you are working with classes and constructor objects more than ever. Class-transformer allows you to transform plain object to some instance of class and versa. Also it allows to serialize / deserialize object based on criteria. This tool is super useful on both frontend and backend.
Example how to use with angular 2 in plunker. Source code is available here.
什么是 class-transformer¶
In JavaScript there are two types of objects:
- plain (literal) objects
- class (constructor) objects
Plain objects are objects that are instances of Object
class.
Sometimes they are called literal objects, when created via {}
notation.
Class objects are instances of classes with own defined constructor, properties and methods.
Usually you define them via class
notation.
So, what is the problem?
Sometimes you want to transform plain javascript object to the ES6 classes you have.
For example, if you are loading a json from your backend, some api or from a json file,
and after you JSON.parse
it you have a plain javascript object, not instance of class you have.
For example you have a list of users in your users.json
that you are loading:
And you have a User
class:
You are assuming that you are downloading users of type User
from users.json
file and may want to write
following code:
In this code you can use users[0].id
, you can also use users[0].firstName
and users[0].lastName
.
However you cannot use users[0].getName()
or users[0].isAdult()
because "users" actually is
array of plain javascript objects, not instances of User object.
You actually lied to compiler when you said that its users: User[]
.
So what to do? How to make a users
array of instances of User
objects instead of plain javascript objects?
Solution is to create new instances of User object and manually copy all properties to new objects.
But things may go wrong very fast once you have a more complex object hierarchy.
Alternatives? Yes, you can use class-transformer. Purpose of this library is to help you to map your plain javascript objects to the instances of classes you have.
This library also great for models exposed in your APIs, because it provides a great tooling to control what your models are exposing in your API. Here is an example how it will look like:
Now you can use users[0].getName()
and users[0].isAdult()
methods.
安装¶
Node.js¶
- Install module:
npm install class-transformer --save
reflect-metadata
shim is required, install it too:
npm install reflect-metadata --save
and make sure to import it in a global place, like app.ts:
- ES6 features are used, if you are using old version of node.js you may need to install es6-shim:
npm install es6-shim --save
and import it in a global place like app.ts:
浏览器¶
- Install module:
npm install class-transformer --save
reflect-metadata
shim is required, install it too:
npm install reflect-metadata --save
add <script>
to reflect-metadata in the head of your index.html
:
If you are using angular 2 you should already have this shim installed.
- If you are using system.js you may want to add this into
map
andpackage
config:
方法¶
plainToClass¶
This method transforms a plain javascript object to instance of specific class.
plainToClassFromExist¶
This method transforms a plain object into an instance using an already filled Object which is an instance of the target class.
classToPlain¶
This method transforms your class object back to plain javascript object, that can be JSON.stringify
later.
classToClass¶
This method transforms your class object into a new instance of the class object. This may be treated as deep clone of your objects.
You can also use an ignoreDecorators
option in transformation options to ignore all decorators you classes is using.
serialize¶
You can serialize your model right to json using serialize
method:
serialize
works with both arrays and non-arrays.
deserialize and deserializeArray¶
You can deserialize your model from json using the deserialize
method:
To make deserialization work with arrays, use the deserializeArray
method:
执行类型安全的实例¶
The default behaviour of the plainToClass
method is to set all properties from the plain object,
even those which are not specified in the class.
If this behaviour does not suit your needs, you can use the excludeExtraneousValues
option
in the plainToClass
method while exposing all your class properties as a requirement.
使用嵌套对象¶
When you are trying to transform objects that have nested objects,
it's required to known what type of object you are trying to transform.
Since Typescript does not have good reflection abilities yet,
we should implicitly specify what type of object each property contain.
This is done using @Type
decorator.
Lets say we have an album with photos. And we are trying to convert album plain object to class object:
提供多个类型选项¶
In case the nested object can be of different types, you can provide an additional options object,
that specifies a discriminator. The discriminator option must define a property
that holds the subtype
name for the object and the possible subTypes
that the nested object can converted to. A sub type
has a value
, that holds the constructor of the Type and the name
, that can match with the property
of the discriminator.
Lets say we have an album that has a top photo. But this photo can be of certain different types.
And we are trying to convert album plain object to class object. The plain object input has to define
the additional property __type
. This property is removed during transformation by default:
JSON input:
Hint: The same applies for arrays with different sub types. Moreover you can specify keepDiscriminatorProperty: true
in the options to keep the discriminator property also inside your resulting class.
公开 getters 和方法返回值¶
You can expose what your getter or method return by setting an @Expose()
decorator to those getters or methods:
公开具有不同名称的属性¶
If you want to expose some of the properties with a different name,
you can do that by specifying a name
option to @Expose
decorator:
跳过特定属性¶
Sometimes you want to skip some properties during transformation.
This can be done using @Exclude
decorator:
Now when you transform a User, the password
property will be skipped and not be included in the transformed result.
操作的跳过依赖关系¶
You can control on what operation you will exclude a property. Use toClassOnly
or toPlainOnly
options:
Now password
property will be excluded only during classToPlain
operation. Vice versa, use the toClassOnly
option.
跳过类的所有属性¶
You can skip all properties of the class, and expose only those are needed explicitly:
Now id
and email
will be exposed, and password will be excluded during transformation.
Alternatively, you can set exclusion strategy during transformation:
In this case you don't need to @Exclude()
a whole class.
跳过私有属性或某些前缀属性¶
If you name your private properties with a prefix, lets say with _
,
then you can exclude such properties from transformation too:
This will skip all properties that start with _
prefix.
You can pass any number of prefixes and all properties that begin with these prefixes will be ignored.
For example:
使用组来控制排除的属性¶
You can use groups to control what data will be exposed and what will not be:
使用版本控制来控制公开的和被排除的属性¶
If you are building an API that has different versions, class-transformer has extremely useful tools for that. You can control which properties of your model should be exposed or excluded in what version. Example:
Сonverting 日期字符串到日期对象¶
Sometimes you have a Date in your plain javascript object received in a string format.
And you want to create a real javascript Date object from it.
You can do it simply by passing a Date object to the @Type
decorator:
Same technique can be used with Number
, String
, Boolean
primitive types when you want to convert your values into these types.
使用数组¶
When you are using arrays you must provide a type of the object that array contains.
This type, you specify in a @Type()
decorator:
You can also use custom array types:
Library will handle proper transformation automatically.
ES6 collections Set
and Map
also require the @Type
decorator:
额外的数据转换¶
基本用法¶
You can perform additional data transformation using @Transform
decorator.
For example, you want to make your Date
object to be a moment
object when you are
transforming object from plain to class:
Now when you call plainToClass
and send a plain representation of the Photo object,
it will convert a date value in your photo object to moment date.
@Transform
decorator also supports groups and versioning.
高级用法¶
The @Transform
decorator is given more arguments to let you configure how you want the transformation to be done.
Argument | Description |
---|---|
value |
The property value before the transformation. |
key |
The name of the transformed property. |
obj |
The transformation source object. |
type |
The transformation type. |
options |
The options object passed to the transformation method. |
其他修饰符¶
Signature | Example | Description |
---|---|---|
@TransformClassToPlain |
@TransformClassToPlain({ groups: ["user"] }) |
Transform the method return with classToPlain and expose the properties on the class. |
@TransformClassToClass |
@TransformClassToClass({ groups: ["user"] }) |
Transform the method return with classToClass and expose the properties on the class. |
@TransformPlainToClass |
@TransformPlainToClass(User, { groups: ["user"] }) |
Transform the method return with plainToClass and expose the properties on the class. |
The above decorators accept one optional argument: ClassTransformOptions - The transform options like groups, version, name
An example:
the user
variable will contain only firstName,lastName, email properties because they are
the exposed variables. email property is also exposed because we metioned the group "user.email".
使用泛型¶
Generics are not supported because TypeScript does not have good reflection abilities yet. Once TypeScript team provide us better runtime type reflection tools, generics will be implemented. There are some tweaks however you can use, that maybe can solve your problem. Checkout this example.
隐式类型转换¶
NOTE If you use class-validator together with class-transformer you propably DON'T want to enable this function.
Enables automatic conversion between built-in types based on type information provided by Typescript. Disabled by default.
它如何处理循环引用?¶
Circular references are ignored.
For example, if you are transforming class User
that contains property photos
with type of Photo
,
and Photo
contains link user
to its parent User
, then user
will be ignored during transformation.
Circular references are not ignored only during classToClass
operation.
例子与 Angular2¶
Lets say you want to download users and want them automatically to be mapped to the instances of User
class.
You can also inject a class ClassTransformer
as a service in providers
, and use its methods.
Example how to use with angular 2 in plunker. Source code is here.
样品¶
Take a look on samples in ./sample for more examples of usages.
发布说明¶
See information about breaking changes and release notes here.