Как восстановить набранные данные?


Проблема

У меня есть простой блог с файлом JSON, используемым в качестве базы данных. Я хотел бы получить все посты и отобразить их в виде списка.

Ниже вы можете увидеть мой интерфейс Post:

interface Post {
  authorId: number;
  title: string;
  tags: string[];
  content: string;
  state: 'draft' | 'published';
  createdAt: Date;
  modifiedAt: Date;
  publishedAt: Date | null;
}
Вход в полноэкранный режим Выход из полноэкранного режима

А это представление базы данных в JSON:

{
  "posts": [{
    "authorId": 7,
    "title": "My first post",
    "tags": [],
    "content": "Hello world!",
    "state": "draft",
    "createdAt": "2022-05-20T17:21:34.000Z",
    "modifiedAt": "2022-05-23T18:45:17.000Z",
    "publishedAt": null
  }]
}
Войти в полноэкранный режим Выход из полноэкранного режима

Когда я разбираю это с помощью JSON.parse, я получаю несоответствие типов createdAt, modifiedAt и publishedAt, поскольку все они являются строками вместо объектов Date.

Вопрос в том, как исправить это несоответствие?


Решение

Первая идея, которая приходит в голову, это map над списком и вручную преобразовать его в соответствующие объекты

const parsedData = JSON.parse(jsonData);

const data = {
  posts: parsedData.posts.map((post) => {
    return {
      ...post,
      createdAt: new Date(post.createdAt),
      modifiedAt: new Date(post.modifiedAt),
      publishedAt: post.publishedAt ? new Date(post.publishedAt) : null
    };
  })
};
Войдите в полноэкранный режим Выйти из полноэкранного режима

Это решение работает, но есть одна проблема: Мне нужно повторять это преобразование каждый раз, когда я хочу получить объекты Post. Кроме того, после внесения изменений в интерфейс Post мне нужно отразить их во всех местах.

Давайте немного улучшим это.

Создание функции

Я собираюсь извлечь код преобразования в функции для уменьшения количества повторений. Это также упростит обслуживание.

function parsePost(post) {
  return {
    ...post,
    createdAt: new Date(post.createdAt),
    modifiedAt: new Date(post.modifiedAt),
    publishedAt: post.publishedAt ? new Date(post.publishedAt) : null
  };
}

function parsePosts(list) {
  return list.map(parsePost);
}
Вход в полноэкранный режим Выйти из полноэкранного режима

Я могу свободно использовать эту функцию по мере необходимости:

const parsedData = JSON.parse(jsonData);
const data = {
  posts: parsePosts(parsedData.posts)
};
Войти в полноэкранный режим Выйти из полноэкранного режима

Использование библиотеки

Хотя текущее решение работает, является простым и многоразовым, я могу пойти на шаг дальше.

Некоторое время назад я нашел интересную библиотеку, которая позволяет сериализовать JS-объекты и сохранять информацию о его типе. Ей было несколько лет, поэтому я решил создать ее современную версию.

Позвольте представить вам: hydration-next.


В самом начале мне нужно добавить информацию о типе в мой пост. Для этого я могу использовать функцию dehydrate. Она возвращает объект с дополнительным полем _types. Существует также функция stringify, которая является сокращением для JSON.stringify(dehydrate(data)).

Здесь вы можете увидеть, как теперь выглядит мой JSON:

{
  "authorId": "7",
  "title": "My first post",
  "tags": {},
  "content": "Hello world!",
  "state": "draft",
  "createdAt": 1653067294000,
  "modifiedAt": 1653331517000,
  "publishedAt": "",
  "_types": {
    "authorId": "number",
    "title": "string",
    "tags": "array",
    "content": "string",
    "state": "string",
    "createdAt": "Date",
    "modifiedAt": "Date",
    "publishedAt": "null"
  }
}
Вход в полноэкранный режим Выход из полноэкранного режима

Я могу безопасно хранить его в файле, локальном хранилище или где-то еще.

Для другого способа я могу использовать функцию hydrate. Аналогично, существует функция parse, которая является сокращением для hydrate(JSON.parse(data)).

Примитивные типы данных (string, boolean, number, null) поддерживаются из коробки, а также массивы, объекты, Date, RegExp и Buffer. Вы также можете добавлять пользовательские типы и определять функции для их увлажнения и обезвоживания.

Здесь вы можете увидеть предыдущий пример, на этот раз с hydration-next:

import { parse } from 'hydration-next';

// ...

const data = parse(jsonData);
Вход в полноэкранный режим Выход из полноэкранного режима

Конец

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

Увидимся в следующий раз!

Оцените статью
Procodings.ru
Добавить комментарий