2

I have a set of classes with a fairly straightforward set of fields:

interface IQuiz {
    name: string;
    questions: Question[];
    score(): number;
}
export class Quiz implements IQuiz {
    name: string;
    questions: Question[];
    score(): number {
        var theScore: number = 0;
        this.questions.forEach(question => (theScore += question.value));
        return theScore;
    }
}

interface IQuestion {
    text: string;
    value: number;
}
export class Question {
    text: string;
    value: number;
}

Then I have some JSON which represents some instances of those objects. This JSON includes values for Quiz.name, an array of Quiz.questions each with values for their text and value fields.

Somewhere else, I have a reference to this Quiz class that has been created from JSON.parse(json) like the code below:

var json = '{"name": "quizA", "questions": [{"text": "Question A", "value": 0 }, ... ]}'
var quiz = <IQuiz>JSON.parse(json);

// Some other stuff happens which assigns values to each question

var score = quiz.score(); // quiz.score is not a function

It seems the deserialized object is not actually an implementation of the interface provided.

How do I get a reference to an instance of the correct interface, so that I can call quiz.score() and it actually call the method?

Jaymz
  • 6,140
  • 2
  • 26
  • 30
  • Putting `` before an expression doesn't turn an object into an instance of that interface. It just tells the TypeScript compiler to _assume_ that it is an instance of that interface. For an answer to your question: http://stackoverflow.com/questions/5873624/parse-json-string-into-a-particular-object-prototype-in-javascript – JLRishe Apr 22 '16 at 09:33
  • Thanks, I saw that question and am still hoping there's a better answer I guess. Otherwise it looks like I'll need to create a constructor for each object that takes the parsed object (or it's properties), and maps them in. Simple for the object in this question, but tedious for more complex object graphs... – Jaymz Apr 22 '16 at 10:52

1 Answers1

1

There is no need of interfaces, it will add twice the work for maintaining your model's properties. Add a constructor in your Quiz class so that it extends your json object.

export class Quiz {
    constructor( json: any )
    {
      $.extend(this, json);

      // the same principle applies to questions:
      if (json.questions)
        this.questions = $.map( json.questions, (q) => { return new Question( q ); } );
    }
    name: string;
    questions: Question[];
    score(): number { ... }
}

In your ajax callback, create the Quiz object from your json Object:

let newQuiz = new Quiz( jsonQuiz );
let score = newQuiz.score();

I detailed the solution in that post.

Community
  • 1
  • 1
Anthony Brenelière
  • 60,646
  • 14
  • 46
  • 58