Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Typescript, serialize class objects

How do I serialize these classes to JSON?

As you can see from the example below JSON.stringify() does not serialize the list of Cache_Backend_LocalStorage_Tag inside the Cache_Backend_LocalStorage_TagThree object.

What am I missing?

interface Cache_Backend_LocalStorage_Tag_Interface {
    _tag : string;
    _keys : string[];
}

class Cache_Backend_LocalStorage_Tag implements Cache_Backend_LocalStorage_Tag_Interface {

    public _tag : string;
    public _keys : string[];

    constructor(tag : string) {
        this._tag = tag;

        this._keys = [];
    }

    public add(key : string) : void {
        this._keys.push(key);   
    }

    public remove(key : string): boolean {
        // Get the index of the key
        var index = this._keys.indexOf(key, 0);

        // Check if we found the keys index
        if (index != undefined) {
           this._keys.splice(index, 1);

           return true;
        }

        return false;
    }

    public get tag(): string {
        return this._tag;
    }

    public get keys(): string[] {
        return this._keys;
    }
}

interface Cache_Backend_LocalStorage_TagThree_Interface {
    _tags : Cache_Backend_LocalStorage_Tag[];
}

class Cache_Backend_LocalStorage_TagThree implements Cache_Backend_LocalStorage_TagThree_Interface {

    public _tags : Cache_Backend_LocalStorage_Tag[];

    constructor(tags : Cache_Backend_LocalStorage_Tag[] = []) {
        this._tags = tags;
    }

    public add(tag : Cache_Backend_LocalStorage_Tag) : void {
        this.tags[tag.tag] = tag;
    }

    public get tags(): Cache_Backend_LocalStorage_Tag[] {
        return this._tags;
    }

    public get(tagKey : string): Cache_Backend_LocalStorage_Tag {
        return this.tags[tagKey];
    }

    public addKeyToTag(tagKey, key) {
        this.tags[tagKey].add(key);
    }

    public removeKeyFromTag(tagKey, key) {
        // Get the tag
        var tag = this._tags[tagKey];

        // Check if we found the tag index
        if (tag != undefined) {
            return tag.remove(key);
        }

        return false;
    }

    public clear(tagKey : string): void {
        delete this._tags[tagKey];
    }

    public static fromObject(object): Cache_Backend_LocalStorage_TagThree {
        return new Cache_Backend_LocalStorage_TagThree(object._tags);
    }
}

Issue:

var tagThree = new Cache_Backend_LocalStorage_TagThree();
tagThree.add(new Cache_Backend_LocalStorage_Tag("stores"));
tagThree.addKeyToTag("stores", "store5");
tagThree.removeKeyFromTag("stores", "store5");

//  {"_tags":[]}
console.log(JSON.stringify(tagThree));

// { _tags: [ stores: { _tag: 'stores', _keys: [Object] } ] }
console.log(tagThree);
like image 448
user634545 Avatar asked Mar 23 '15 15:03

user634545


1 Answers

Reason

It's because you're assigning properties to an array and array properties won't be included in JSON serialization. For example:

var a = [];
a["test"] = "some value";
JSON.stringify(a); // returns: []

You need to use a plain object:

var o = {};
o["test"] = "some value";
JSON.stringify(o); // returns: {"test":"some value"} 

Solution

Change your Cache_Backend_LocalStorage_TagThree_Interface interface to use a dictionary like object:

interface Cache_Backend_LocalStorage_TagThree_Interface {
    _tags : { [tag: string] : Cache_Backend_LocalStorage_Tag; };
}

Then update all areas of the code that will now have a compile error to use the same type. For example, change:

constructor(tags : Cache_Backend_LocalStorage_Tag[] = []) {

To:

constructor(tags : { [tag: string] : Cache_Backend_LocalStorage_Tag; } = {}) {

Just for fun - Changing default serialization behaviour (Not recommended)

If you really want to make this work with an array with your current setup (I'm not sure why), you can override how serialization is done. To do this, add a toJSON method to the _tags array in Cache_Backend_LocalStorage_TagThree. This allows you to control how the object is serialized when JSON.stringify is called on it. For example:

this._tags.toJSON = function() {
    var values = [];

    for (var v in this) {
        if (this[v] instanceof Cache_Backend_LocalStorage_Tag) {
            values.push(this[v]);
        }
    }

    return JSON.stringify(values);
};
like image 104
David Sherret Avatar answered Sep 17 '22 13:09

David Sherret