How to use the new getter and setter?

Please help me refactor the code. I wrote a component that is a form for sending questions. It also displays the questions asked at the moment (so far in the console, but this is not important). Instead of a database, I use localstorage for training purposes.

So, here is my service that works with the "database":

@Injectable()
export class QuestionsService {

    private questions: Question[];

  constructor() { 
    this.questions = localStorage.questions ? JSON.parse(localStorage.questions) : [];
  }

  getQuestions() {
    console.log('qqq');
    return this.questions;
  };  

  setQuestions(question): void {
    this.questions.push(question);
    localStorage.questions = JSON.stringify(this.questions);
  };    

}

Here is the described type:

export class Question {
    text: string;
    speakerId: number;
    dateHuman: string;
    dateUnix: string;
}

Here is the component:

export class QuestionComponent implements OnInit {

  private questions: Question[] = [];

  constructor(private questionsService: QuestionsService) { }

  ngOnInit() {   
    this.getQuestions();
    console.log(this.questions);
  }   

  private sendQuestion(): void {   
    this.questionsService.setQuestions({
      "text": "42256yregd",
      "speakerId": 23,
      "dateHuman": "223 oct",
      "dateUnix": "22222"
    });
  };

  private getQuestions(): void {
    this.questionsService.getQuestions().map(question => {
      this.questions.push(question);
     });   
  };   

}

This system works. But I would like to use the new fashionable getters and setters from the es6 standard. Here is my attempt:

Service:

    private questions: Question[];

  constructor() { 
    this.questions = localStorage.questions ? JSON.parse(localStorage.questions) : [];
  }

  get questions() {
    console.log('qqq');
    return this.questions;
  };  

  set questions(question): void {
    this.questions.push(question);
    localStorage.questions = JSON.stringify(this.questions);
  };

Component:

....
..

  private sendQuestion(): void {   
    this.questionsService.questions = {
      "text": "42256yregd",
      "speakerId": 23,
      "dateHuman": "223 oct",
      "dateUnix": "22222"
    };
  };

  private getQuestions(): void {
    this.questionsService.questions().map(question => {
      this.questions.push(question);
     });   
  };  

....
....

But the console outputs an error:

Duplicate identifier 'questions'.

Author: A K, 2017-10-25

2 answers

Your problem is this:

private questions: Question[];  // раз

get questions() { // два
set questions(question): void {

You have two properties declared with the same name. You can't do that, which is what the tsc tells you. This problem is solved by adding a prefix to the private property:

private _questions: Question[];

get questions() {
set questions(question): void {
 2
Author: Pavel Mayorov, 2017-10-26 10:26:07

Here

get questions() {
  ...
  return this.questions;
};

You use the closure to recursively call the getter questions. It does not reach the return value, because the maximum stack of the recursive function call is exceeded.

The interpreter does not understand the entry this.questions as " refer to the property questions object this", and as "get the value of the property questions of the object this". And the value is obtained by referring to the getter, which in this case has the same name as itself the questions property, which leads to an incorrect result (to "infinite" recursion). You will eventually be issued a warning about this.

No.

So would be if the interpreter did not stop such behavior on its own. In fact, it doesn't even come to recursive calls, because the interpreter (compiler) immediately detects that you have a name collision in your code - the property name matches the name of the getter.

In the case of a setter, by addressing inside it, you do not directly address the this.questions property to this.questions, but, because of the presence of the getter, first to it [the getter]. Accordingly, logically, you also redefine not a property, but a getter.

But, again, judging by the error you received, this behavior is still somehow intercepted by something. Otherwise, we might have been wondering for quite some time what the problem was. Well, or just get an error like the one described above.

Decision problems

In any case, your problem is solved by distinguishing between the property name and its accessors (getters and setters). Ideally, you should make the property itself private, and the getter and setter public. However, since ECMAScript does not provide access restrictions as such (even its 6th version), you will have to rely on the integrity of those who use your code. Namely, , give the property the name _questions, and getter and setter - just questions.

Thus, you kill two birds with one stone: you get rid of unwanted behavior and explicitly indicate that the property itself is private (or protected).

Please note that, in fact, you can use any name, and the option with an underscore I gave as the most correct (for a number of reasons described above).

Based on all that said, your getter and setter should look something like this (respectively):

get questions() {
  console.log('qqq');
  return this._questions; // добавлено нижнее подчеркивание
};  

set questions(question): void {
  this._questions.push(question);
  localStorage.questions = JSON.stringify(this.questions);
};
 1
Author: smellyshovel, 2017-10-26 13:11:32