2013-05-28 8 views
12
initialisieren

Ich verwende TypeScript, um einige Klassen mit KnockoutJS zu erstellen, wobei die Daten von JSON geladen werden, die von WebAPI zurückgegeben werden.Typoskript-Klassenwerte aus Konstruktor

Das Problem ist, ich wollte die JSON-Werte in meine TypeScript-Klasse aus dem Konstruktor kopieren: aber wenn ich dies nur an der Basisklasse tun, wurden die geerbten Eigenschaften nicht definiert und daher nicht initialisiert.

Beispiel

Wir wollen eine Bestandsaufnahme Element aus einer JSON-Antwort erstellen:

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

Ich habe eine Basisklasse Produkt und eine vererbte Klasse 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 
    } 
} 

Die Eigenschaften für Inventar wird nur in dem JS-Ausgabecode nach dem Super Konstruktoraufruf erstellt, also nicht vorhanden, wenn das Produktkonstrukt oder wird ausgeführt.

Die einzige Lösung, die ich sehen kann, ist, den Initialisierungswert aus dem Konstruktor herauszunehmen, aber ich mag diesen Ansatz nicht wirklich, obwohl ich vermute, dass es die einzige Option ist.

var inventoryItem = new Inventory(); 
    inventoryItem.LoadFrom(source); 
+0

Welchen Zweck hat das Kopieren von Eigenschaften in die Basisinstanz? Ist es schlecht, wenn Menge und Preis nach der Kopie definiert sind? – BSick7

+0

Ich bin mir nicht sicher, ob ich verstehe, was das Problem ist. Der Konstruktor von 'Product' sollte' Name' aus 'source' setzen und der Konstruktor von' Inventory' sollte 'Menge' und' Preis' aus 'source' setzen. – MiMo

+0

Das Problem ist, dass Sie die Kopiereigenschaften zweimal aufrufen müssen: was macht keinen Sinn. Wenn Sie es gerade in der Produktklasse getan haben, wurde nur Name festgelegt. Wenn Sie dies nur in Inventory getan haben, rufen Sie es nicht in Product auf, so dass alles, was ein Produkt erstellt, nicht initialisiert wird. – Quango

Antwort

8

Best I kommen kann mit Ihnen eine Basis Deserialisierung Routine haben, damit die von der Konstruktor aufgerufen wird, wird dieser (modifizierte Knockout zu entfernen Abhängigkeit zum Testen):

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

Es ist odd, dass die Variablen nur im JS nach dem Aufrufinitialisiert. Vielleicht im Wert von raising a work item on codeplex?

Playground.

+0

Danke für den Vorschlag: Einen solchen Initialisierer zu haben ist eine gute Alternative. Ich glaube nicht, dass es sich um einen Fehler in TypeScript handelt, da ich davon ausgehe, dass es so funktioniert. Es ist die dynamische Natur von JS: Es gibt keine Metadaten und Reflektionen, um zu funktionieren, im Gegensatz zu C# usw. – Quango

+0

Einverstanden. Eine Kuriosität, eher als ein Fehler. – JcFx

3

Dieser Ansatz scheint für mich zu arbeiten:

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

Danke .. das würde auch funktionieren, aber sobald Sie beginnen, eine Menge Variablen hinzuzufügen, macht es für langwierige Codierung. Ich werde die Idee von JcFX zuerst ausprobieren – Quango

Verwandte Themen