typesafe-mapper v0.0.1
Typesafe-ish Object Mapper
Introduction
This was a total learning effort as I wanted to practice using ORM's but quickly realised I needed a way to get my JSON objects into orm decorated classes. This means that this is extremely opinionated regarding the things it will and will not map (and return types as the note explains below).
After checking out github I found this project which did almost exactly what I needed... But I didn't understand how it worked at all! So I decided to try and replicate this functionality (consulting their great code for help) to help my understanding. They have slightly different behaviour but the linked solution is more elegant and configurable than this one, I highly recommend you check them out before this!
This though, how does it work?
Decorators are explained in the TypeScript docs. This project also uses reflect-metadata.
Be warned there is a liberal use of null
in this project. I have read in many places that this is poor practice, but this was specifically created to be used in conjuction with an orm. I figured that I would leave the null checking to the orm rather than throwing undefined around.
The Decorators
Any decorated property will be mapped. The decorator function accepts either an object (with optional properties name
and _class
), a string (which will become name
internally), or no arguments.
The definition for the decorator is:
@MapProperty<T>({
name?: string,
_class?: { new (): T };
})
It can be used on the following ways:
@MapProperty()
to map by key with no support for arrays.@MapProperty('foo')
to map a property from the source object with keyfoo
.@MapProperty({_class: Bar})
to map an array property where each element will be mapped based on decorated classBar
.@MapProperty({name: foo, _class: Bar})
to map an array property from the source object with keyfoo
where each element is the decorated classBar
.
_class
only needs to be provided for array properties. This is because in it's current form, Typescript decorators do not capture the underlying type of array elements. If this changes, this will become obselete.
The Logic
If _class
is not provided but an array is decorated, an Error
will be thrown.
If an array on the source object is an array of primitives then _class
must be the corresponding boxed primitive; but these will still be mapped using their primitive type. Example:
class PrimitivesArray {
@MapProperty({ _class: String })
array1: string[] = [];
}
const srcObj = {
array1: ["foo", "bar"]
}
const mappedObj = Mapper.mapObject(PrimitivesArray, srcObj);
const console.log(typeof mappedObj.array1[0]);
// returns string
When mapping non-array properties by key, it is sufficient to decorate properties with @MapProperty()
and no further arguments.
The Nulls
null
will be returned from .mapObject
if either of the arguments are null
or undefined
.
A decorated property will be set to null :
- If addressing it on the source object returns
undefined
. - If the primitive types do not match.
A decorated array will have it's elements set to null when the corresponding array element on the source object does not match the declared type.
So how can I use it?
To decorate your class:
import { MapProperty } from 'typesafe-mapper'
class exampleClass {
@MapProperty()
name: string
}
Just import the main file into your project and call the mapObject
method:
import Mapper from 'typesafe-mapper';
const mappedObject = Mapper.mapObject(targetClass, sourceObject);
Where targetClass is the decorated class type and source is the object with the properties to be extracted.
The poor documentation ends here
6 years ago