web-dev-qa-db-fra.com

Initialisation des valeurs de classe TypeScript à partir du constructeur

J'utilise TypeScript pour créer des classes avec KnockoutJS, les données étant chargées à partir de certains JSON renvoyés par WebAPI.

Le problème est que je voulais copier les valeurs JSON dans ma classe TypeScript à partir du constructeur: mais si je fais cela uniquement à la classe de base, les propriétés héritées n'ont pas été définies et ne sont donc pas initialisées.

Exemple

Nous voulons créer un élément d'inventaire à partir d'une réponse JSON:

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

J'ai un produit de classe de base et une classe héritée Inventaire:

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

Les propriétés pour Inventory ne sont créées dans le code de sortie JS qu'après l'appel du constructeur super . Elles n'existent donc pas lorsque le constructeur Product est exécuté.

La seule solution que je vois est de supprimer la valeur d'initialisation du constructeur, mais je n'aime pas trop cette approche, même si je soupçonne que c'est la seule option.

  var inventoryItem = new Inventory();
  inventoryItem.LoadFrom(source);
13
Quango

Le mieux que je puisse trouver pour vous permettre d’avoir une routine de désérialisation de base appelée à partir du constructeur est la suivante (modifié pour supprimer la dépendance de masquage pour les tests):

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

Il est impair que les variables ne soient initialisées dans le JS qu'après l’appel de super(). Peut-être que ça vaut soulever un élément de travail sur le codeplex ?

Cour de récréation .

11
Jude Fisher

Cette approche semble fonctionner pour moi:

/// <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
Corey Ford

@JcFx

ce test de variable est toujours indéfini avant que sa valeur ne soit attribuée.

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

vous voudrez peut-être que cette instruction if soit toujours 'true', ou utilisez ceci à la place:

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

c'est à propos, voyez ce lien: https://github.com/angular/tsickle/issues/125

0
Rindra Parama