1

TypeError: this.pizzaPlaceEditService.currentPizzaPlace.getPoint is not a function

I found TypeError: is not a function typescript class but I don't think it applies to this situation. Found several more that didn't seem to apply. Here's my redacted class:

export class PizzaPlace {
  deliveryArea = [];

  getPoint(seq: number): Point {
    let result: Point = null;

    this.deliveryArea.forEach(function(point:Point) {
      if(seq == point.sequence) {
        result = point;
      }
    });

    return result;
  }

}

Here is my working unit test:

  it('should retrieve a point by sequence', () => {
    var point1 = new Point();
    point1.sequence = 0;
    point1.latitude = 5.12;
    point1.longitude = 5.12;

    var point2 = new Point();
    point2.sequence = 1;
    point2.latitude = 6.13;
    point2.longitude = 6.13;

    var point3 = new Point();
    point3.sequence = 2;
    point3.latitude = 5.25;
    point3.longitude = 5.25;

    pizzaPlace.deliveryArea = [point1, point2, point3];

    expect(pizzaPlace.getPoint(0)).toBe(point1);
    expect(pizzaPlace.getPoint(1)).toBe(point2);
    expect(pizzaPlace.getPoint(2)).toBe(point3);
    expect(pizzaPlace.getPoint(3)).toBe(null);
  });

Here is the code generating the error:

  onDownClick(): void {
    if(this.selectedPoint) {
      let currSeq = this.selectedPoint.sequence;
      let nextSeq = currSeq + 1;
      console.log("Current pizza place:" + JSON.stringify(this.pizzaPlaceEditService.currentPizzaPlace));
      console.log("nextSeq:" + nextSeq);
      let next = this.pizzaPlaceEditService.currentPizzaPlace.getPoint(nextSeq);
      if(next) {
        this.pizzaPlaceEditService.currentPizzaPlace.swapPoints(this.selectedPoint, next);
      }
    }
  }

And here is the error:

Current pizza place:{"contactName":"Zaphod Beeblebrox","customerId":"TPGup2lt","deliveryArea":[{"errorMsg":"","sequence":0,"latitude":34.552,"longitude":-84.556},{"errorMsg":"","sequence":1,"latitude":34.711,"longitude":-84.665}],"deliveryZips":[],"paypalAccount":"HB17","settings":null,"shopName":"Donato's Hartland","shopStreet":"1531 Kenesaw Dr","shopCity":"Lexington","shopState":"KY","shopZip":"40515","shopPhone":"(859)555-2637","billStreet":"1531 Kenesaw Dr","billCity":"Lexington","billState":"KY","billZip":"40515","billPhone":"(859)555-2637"}
pizza-place-delivery.component.ts:63:6
nextSeq:1
pizza-place-delivery.component.ts:64:6
TypeError: this.pizzaPlaceEditService.currentPizzaPlace.getPoint is not a function

I have run out of things to try. Any advice appreciated!

Thom
  • 14,013
  • 25
  • 105
  • 185
  • 1
    `this.pizzaPlaceEditService.currentPizzaPlace` object has only data, and no methods. Most likely, it was not created as an instance of `PizzaPlace` class - maybe you are deserializing it from JSON ? – artem Mar 08 '18 at 00:17
  • @artem That is absolutely correct. Please post as an answer and I will mark it, especially if you tell me how to fix the type after I've loaded it from JSON. – Thom Mar 08 '18 at 00:20
  • @artem I thought that javascript did Duck typing and that if I told it it was a pizza place that it would call the method correctly. You can cover that in your answer as well. ;) – Thom Mar 08 '18 at 00:21
  • 1
    Sorry I don't have time for writing answers right now. "I told it it was a pizza place" can mean several things, but if it was a type assertion for TypeScript compiler, it's for compile time only and it's not supposed to add anything, methods or anything else, to the object at runtime. The question "how to get class from JSON" was asked many times, see for example https://stackoverflow.com/questions/29758765/json-to-typescript-class-instance or https://stackoverflow.com/questions/22885995/how-do-i-initialize-a-typescript-object-with-a-json-object – artem Mar 08 '18 at 00:26
  • @artem Posted my own answer. Thanks so much for taking the time to help. – Thom Mar 08 '18 at 14:47

1 Answers1

2

Thanks to Artem's excellent input, I was able to figure out that the problem was caused by the fact that I was creating an object from the JSON instead of the object that I wanted and so it was a different type. Evidently, Classes in Typescript are compile time only and are discarded at runtime.

So, based on: How do I initialize a TypeScript object with a JSON object option 4 of the selected answer, I created a serializable.ts.

export interface Serializable<T> {
  deserialize(input: Object): T;
}

And then modified my class with the implements:

export class PizzaPlace implements Serializable<PizzaPlace> {

and then added:

  deserialize(input): PizzaPlace {
    this.paypalAccount = input.paypalAccount;
    this.customerId = input.customerId;
    ...
    this.settings = input.settings;

    return this;
  }

Then, since my web service returns an array of these, I changed my service call:

  .subscribe(places => this.deserializePlaces(places));

and added a new function:

  deserializePlaces(places: Object[]){
    this.pizzaPlaces = [];

    places.forEach(obj=> {
      let place = new PizzaPlace().deserialize(obj);
      this.pizzaPlaces.push(place);
    });
  }

And this seems to work just fine. Thanks for the input.

Thom
  • 14,013
  • 25
  • 105
  • 185