Как использовать геттеры и сеттеры из es6?

386
27 октября 2017, 14:41

Помогите пожалуйста решить проблему. Есть компонент, который представляет из себя форму для отправки вопросов. Так же он выводит заданные на настоящий момент вопросы(пока в консоль, но это не принципиально). Вместо базы данных для учебных целей использую localstorage.

Сервис:

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

Компонент:

private questions: Question[] = [];
constructor(private questionsService: QuestionsService) { }
ngOnInit() {     
  this.getQuestions();
  console.log(this.questions);
}  
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);
   });   
};

Тип:

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

Ошибка, которую выводит консоль:

ERROR in /home/kalinin/angular2/PRACTICE/feedback/src/app/services/questions.service.ts (19,7): A 'set' accessor cannot have a return type annotation.
ERROR in /home/kalinin/angular2/PRACTICE/feedback/src/app/services/questions.service.ts (20,26): Argument of type 'Question[]' is not assignable to parameter of type 'Question'.
  Property 'text' is missing in type 'Question[]'.
ERROR in /home/kalinin/angular2/PRACTICE/feedback/src/app/question/question.component.ts (62,7): Type '{ "text": string; "speakerId": number; "dateHuman": string; "dateUnix": string; }' is not assignable to type 'Question[]'.
  Object literal may only specify known properties, and '"text"' does not exist in type 'Question[]'.
ERROR in /home/kalinin/angular2/PRACTICE/feedback/src/app/question/question.component.ts (72,5): Cannot invoke an expression whose type lacks a call signature. Type 'Question[]' has no compatible call signatures.
Answer 1

Важное отличие TypeScript от JavaScript - возможность указать тип.

При этом, при несоответствии типов компилятор выкинет ошибку, аналогичную ошибке в вопросе.

Так как в коде:

get questions() {
set questions(question) {

Не указаны типы, компилятор выводит их сам, и на основании правил для определения свойств, получает следующее:

get questions(): Question[] {
set questions(question: Question[]) {

Таким образом, при вызове

.questions = {
    "text": "42256yregd",
    "speakerId": 23,
    "dateHuman": "223 oct",
    "dateUnix": "22222"
  }

Идет попытка сопоставить присваиваемый объект типу Question[] и происходит неудача, так как у объект не является массивом элементов, а соответствует всего одному элементу.

При этом, указать в сеттере тип параметра как один объект

set questions(question: Question) {

нельзя, так как по правилам, типы сеттера и геттера должны совпадать.

Для решения проблемы вместо сеттера нужно было сделать метод для добавления вопросов.

Альтернативным решением может быть использованием union-типов. Но в этом случае, внутри тела необходимо проверять какой именно тип все-таки пришел, например:

get questions(): Question|Question[] {
  return this.questions_;
};  
set questions(question: Question|Question[]) {
  if(!Array.isArray(question)){
      this.questions_.push(question);
      localStorage.questions = JSON.stringify(this.questions_);
  }
};

Либо если гарантируется, что сеттер вызываться будет только с одним элементом, то можно использовать подсказку компилятору:

set questions(question: Question|Question[]) {
    this.questions_.push(<Question>question);
    localStorage.questions = JSON.stringify(this.questions_);
};
READ ALSO
Почему нельзя обратиться через точку к свойству объекта?

Почему нельзя обратиться через точку к свойству объекта?

У меня есть сервис, который возвращает объект с датами:

287
Объясните, пожалуйста, про Array.prototype.filter.call()

Объясните, пожалуйста, про Array.prototype.filter.call()

Есть такой кусочек кода, который отстортировывает все div'ыМне непонятно:

346
Поправить выпадающий список

Поправить выпадающий список

нужно что бы когда я начинаю вводить в поле город - в подсказке всплывали не все, а только начинающиеся на введенную букву

285