Initializing Typescript class values from constructor

二次信任 提交于 2020-01-03 07:28:14

问题


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

回答1:


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.




回答2:


This approach seems to work for me:

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



回答3:


@JcFx

this variable test always undefined before it's value assigned.

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

you might want to make this if statement always 'true', or use this instead:

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

it's about forin, see this link: https://github.com/angular/tsickle/issues/125



来源:https://stackoverflow.com/questions/16793503/initializing-typescript-class-values-from-constructor

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!