- Does not require typescript or reflect-metadata;
- Can transform
Array
toSet
and vice versa; - Can transform
Map
toObject
and vice versa; - Can transform
String
orNumber
toDate
; - Provides basic validation;
- Works in all runtimes (Node.js, Web, e.t.c);
- Well typed.
interface Transformer {
fromJSON<T>(json: JSON, Class: { new(): T }): T
toJSON(instance: Object): JSON
}
Transformer is based on JavaScript types, which means that all properties of the target class must be initialized with default values. See examples below.
import { Transformer } from 'kr-transformer'
class User {
name = '' // will be treated as type "String"
age = 0 // will be treated as type "Number"
student = false // will be treated as type "Boolean"
setName() {
// ...
}
}
const json = { name: 'John', age: 42, student: true }
const instance = Transformer.fromJSON(json, User)
const plain = Transformer.toJSON(instance)
console.log(instance instanceof User, instance) // true User { ... }
console.log(plain) // { name: 'John', age: 42, student: true }
The fromJSON
method accepts a third, optional boolean argument, which is true by default, and is responsible for basic validation:
import { Transformer } from 'kr-transformer'
class User {
name = '' // will be treated as type "String"
age = 0 // will be treated as type "Number"
student = false // will be treated as type "Boolean"
setName() {
// ...
}
}
const json = {
name: 'John',
age: "42", // wrong type
student: true
}
try {
const instance = Transformer.fromJSON(json, User, false) // disabling validation
// value from json was used "as is"
console.log(instance) // User { age: '42' ... }
} catch (e) {
console.log(e) // noop
}
try {
const instance = Transformer.fromJSON(json, User)
} catch (e) {
console.log(e) // TransformerError: `Invalid type of "age" in json. User expect type to be "number" but got "string"`
}
import { Transformer } from 'kr-transformer'
class Engine {
volume = 0
start() {}
}
class Car {
vendor = ''
engine = new Engine() // default value is always required
oems: string[] = [] // also initialized with default value
}
const json = {
vendor: 'CoolVendor',
oems: ['aaa', 'bbb'],
engine: {
volume: 2
}
}
const car = Transformer.fromJSON(json, Car)
console.log(car instanceof Car) // true
console.log(car.engine instanceof Engine) // true
console.log(typeof car.engine.start === 'function') // true
console.log(car.oems.pop()) // 'bbb'
Array
->Set
Object
->Map
import { Transformer } from 'kr-transformer'
class Target {
set = new Set<string>()
map = new Map<string, string | number>
}
const json = {
set: ['a', 'b', 'c'],
map: {
a: 1,
b: '2',
c: 3
}
}
const instance = Transformer.fromJSON(json, Target)
console.log(instance) // Target {set: Set(3), map: Map(3)}
const plain = Transformer.toJSON(instance) // { set: ['a', 'b', 'c'], map: { a: 1, b: '2', c: 3 } }
To transform data structures elements we have to declare their types.
To accomplish this, we define a static property called "types" that contains our nested type definitions.
import { Transformer } from 'kr-transformer'
class Bar { a: 1 }
class Baz { b: 2 }
class Qux { c: 3 }
class Foo {
static types = {
array: Bar, // type of elements in array
set: Baz, // type of elements in set
map: Qux // type of elements values in Map
}
// default values are always required
array: Bar[] = []
set: Set<Baz> = new Set()
map: Map<string, Qux> = new Map()
}
const json = {
array: [{ a: 100 }],
// The type of json should be array. Only `Array` can be mapped to `Set`!
set: [{ a: 200 }],
// The type of json should be Object. Only `Object` can be mapped to `Map`!
map: {
1: { c: 300 },
}
}
const result = Transformer.fromJSON(json, Foo)
console.log(result) // Foo { array: [Bar], set: {Baz}, map: { 1 => Qux } }
const plain = Transformer.toJSON(result)
console.log(plain) // { array: [{ a: 100 }], set: [{ a: 200 }], map: { 1: { c: 300 } }}
The static "types" property is not required, if it is not present, the values from json will be used as is.