@MaratMS

Стоит ли использовать классы-обёртки?

Часто в SPA приложениях возникает ситуация, когда структура данных становится сложной. Например, вы запрашиваете через API данные о группах пользователей (будем считать, что бэкэнд написан НЕ на JS), и ответ содержит в себе так же список пользователей, принадлежащей каждой перечисленной группе. Пусть, например, ответ выглядит так:
[
  {
    id: 1,
    name: 'Administrators',
    userList: [
      // ...
    ]
  },
  {
    id: 2,
    name: 'Guests',
    userList: [
      // ...
    ]
  },
]


Не обязательно это должен быть именно API. В таком виде мы можем хранить данные в Redux, например. Проблема в том, что совершенно не очевидно, какие структуры данных приложение ожидает там видеть. И даже навороченный IDE вряд ли сможет вам подсказать, какие данные содержит в себе сущность `userGroup` не говоря уже о вложенных в неё сущностях `user`.
Чтобы сделать код более читаемым, и описать структуру данных я использую классы-обёртки, которые выглядят как-то так (я знаю, про небольшие косяки кода, это просто пример):
export default class UserGroup {
  constructor(groupData = {}) {
    this.id = groupData.hasOwnProperty('id') ? groupData.id : 0;
    this.name = groupData.hasOwnProperty('name') ? groupData.name : '';
    this.userList = groupData.hasOwnProperty('userList') ? groupData.userList : '';
  }

  /**
   * @returns {number}
   */
  get id() {
    return this._id || 0;
  }

  /**
   * @param {number|string} value
   */
  set id(value) {
    this._id = parseInt(value, 10) || 0;
  }

  /**
   * @returns {string}
   */
  get name() {
    return this._name;
  }

  /**
   * @param {string} value
   */
  set name(value) {
    this._name = value;
  }

  /**
   * @returns {User[]}
   */
  get userList() {
    return this._userList;
  }

  /**
   * @param {[]} value
   */
  set userList(value) {
    this._userList = Array.isArray(value) ? value : [];
  }

  /**
   *
   */
  toPlainObject() {
    return {
      id: this.id,
      name: this.name,
      userList: this.userList.map((user) => user.toPlainObject()),
    };
  }

}


Таким образом везде, где будут использоваться эти данные, я буду во-первых: проводить их как `new UserGroup(groupData)`, а во-вторых везде в JsDoc указывать, что это именно `@param {UserGroup}`.

Мне нужно мнение сообщества. Можно ли назвать подобное решение приемлемым? Есть ли какие-либо подводные камни (помимо очевидного повторения кода с бекенда)? Может быть есть другие IDE-френдли способы документировать (а ещё лучше - и валидировать) структуру данных?
  • Вопрос задан
  • 127 просмотров
Пригласить эксперта
Ответы на вопрос 3
Kozack
@Kozack Куратор тега JavaScript
Thinking about a11y
В целом JsDoc должно хватать.

Хм. Я бы на вашем месте, использовал абстракцию + JsDoc
/**
 * @returns {UserGroup}
 */
function getUserGroups () {}

Важно, чтобы получить эти группы можно было исключительно через эту абстракцию. Тогда, я полагаю, любая IDE сможет определить типі и автокомплит
Ответ написан
Комментировать
vabka
@vabka
Токсичный шарпист
Может быть есть другие IDE-френдли способы документировать (а ещё лучше - и валидировать) структуру данных?

Да. Typescript
В вашем случае кода придётся писать сильно меньше, чем без него.
Ответ написан
SilenceOfWinter
@SilenceOfWinter
та еще зажигалка...
адаптер - один из базовых паттернов программирования.
с ide проблем никих если Вы добавите JsDoc к этой структуре.
смотрите реализацию ответов в soap/dom
Ответ написан
Комментировать
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы