Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Initializing Typescript class values from constructor

I'm using TypeScript to create some classes with KnockoutJS, with the data being loaded from some JSON returned by WebAPI.

The problem is I wanted to copy the JSON values into my TypeScript class from the constructor: but if I do this just at the base class, the inherited properties have not been defined and so are not initialised.

Example

We want to create an inventory item from a JSON response:

{ Name: "Test", Quantity:1, Price: 100 }

I have a base class Product and an inherited class Inventory:

export class Product {
  Name = ko.observable("");

  constructor(source) {
    // a utility that copies properties into this instance
    utils.CopyProperties(source,this);
  }

export class Inventory extends Product {
  Quantity = ko.observable(0);
  Price = ko.observable(0);

  constructor(source) {
    super(source); // call base c'tor
    // the quantity and price properties are only now defined
  }
}

The properties for Inventory are only created in the JS output code after the super constructor call, so do not exist when the Product constructor is executed.

The only solution I can see is to take the initialising value out of the constructor, but I don't really like this approach, although I suspect it's the only option.

  var inventoryItem = new Inventory();
  inventoryItem.LoadFrom(source);
like image 866
Quango Avatar asked May 28 '13 13:05

Quango


1 Answers

Best I can come up with to allow you to have a base deserialization routine that is called from the constructor is this (modified to remove knockout dependency for testing):

class utils {
    public static CopyProperties(source:any, target:any):void {
        for(var prop in source){
            if(target[prop] !== undefined){
                target[prop] = source[prop];
            }
            else {
                console.error("Cannot set undefined property: " + prop);
            }
        }
    }
}

class Product {
  Name = "Name";

  constructor(source) {
    this.init(source);
  }

  init(source){
     utils.CopyProperties(source,this);
  }
}

class Inventory extends Product {
  Quantity;
  Price;

  constructor(source) {
    super(source);
  }

  init(source){
      this.Quantity = 0;
      this.Price = 0;
      super.init(source);
  }
}

var item = new Inventory({ Name: "Test", Quantity: 1, Price: 100 });

It is odd that the variables are only initialized in the JS after the call to super(). Maybe worth raising a work item on codeplex?

Playground.

like image 55
Jude Fisher Avatar answered Nov 10 '22 01:11

Jude Fisher