13

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);
4

3 回答 3

11

我能想到的最好的方法是让您拥有一个从构造函数调用的基本反序列化例程(修改以删除用于测试的淘汰赛依赖):

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 });

奇怪的,变量仅在调用 .js 后才在 JS 中初始化super()。也许值得在 codeplex 上提出一个工作项

游乐场

于 2013-05-28T17:06:48.307 回答
3

这种方法似乎对我有用:

/// <reference path="knockout.d.ts" />

export class Product {
    Name: KnockoutObservableString;

    constructor(source) {
        this.Name = ko.observable(source.Name);
    }
}

export class Inventory extends Product {
    Quantity: KnockoutObservableNumber;
    Price: KnockoutObservableNumber;

    constructor(source) {
        super(source);
        this.Quantity = ko.observable(source.Quantity);
        this.Price = ko.observable(source.Price);
    }
}

var item = new Inventory({ Name: "Test", Quantity: 1, Price: 100 });
于 2013-05-28T16:42:53.593 回答
0

@JcFx

此变量 test 在分配值之前始终未定义。

if(target[prop] !== undefined){

您可能希望使此 if 语句始终为“真”,或改用此:

for (const prop of Object.keys(source)) {
  this[prop] = source[prop];
}

这是关于forin的,请参阅此链接: https ://github.com/angular/tsickle/issues/125

于 2018-06-07T09:48:45.627 回答