Skip to content

heruan/type-binder

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

11 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

JavaScript object type binding

npm version CircleCI

Type binding

Given an ES6/TypeScript class

class Person {

    name: string;

    sayHello() {
        return `Hello, my name is ${this.name}!`;
    }

}

from a plain JavaScript object you can easily create an instance of Person

let object = { name: "Foo" }; // or JSON.parse('{ "name": "Foo" }');

let foo = new TypeBinder().bind(object, Person);

foo.sayHello(); // returns "Hello, my name is Foo!"

To bind also object properties, you can use a decorator

import { bind } from "type-binder";

class Person {

    name: string;

    @bind(Person) parent;

}

let foo = new TypeBinder().bind({ name: "Foo", parent: { name: "Bar" } }, Person);

foo.parent.sayHello(); // returns "Hello, my name is Bar!";

This works also with generic typing, using the @generics decorator

import { generics } from "type-binder";

class Person {

    name: string;

    @generics(Person) children: Set<Person>;

}

let foo = new TypeBinder().bind({ name: "Foo", children: [ { name: "Bar" }, { name: "Baz" } ] }, Person);

for (let child of foo.children) {
    child.sayHello();
}

And you can add binding callbacks for additional types

class Person {

    name: string;

    constructor(name: string) {
        this.name = name;
    }

}

let binder = new TypeBinder();

binder.setBindingCallback(Person, object => new Person(object.name));

Object identity

The @identifier decorator takes a function which returns an identifier of that object, which the binder will use to return same instances for all objects with the same identifier (could be scoped, see code).

import { identifier } from "type-binder";

@identifier<Person>(person => person.name)
class Person {

    name: string

}

let binder = new TypeBinder();

let foo1 = binder.bind({ "name": "Foo" }, Person);

let foo2 = binder.bind({ "name": "Foo" }, Person);

foo1 === foo2; // true

Property tracker

Decorating a property with @track will instruct the binder to save the initial property value in the object's metadata.

import { track } from "type-binder";

class Person {

    @track() name: string

}

let person = new TypeBinder().bind({ name: "Foo" }, Person);

person.name = "Bar";

let changed = TypeBinder.propertyHasChanged(person, "name");

changed === true; // true