Недавно мне повезло попасть на проект бэкенд которого написан на php. А как принято у php бекэндов json с ответом они отправляют в snake case стиле. И как следствие вся работа с данными на фронте происходила в перемешку в camel case и snake case стилях. Для решения этой проблемы была доработана библиотека сериализации ts-serializable. Теперь при получении данных из json их можно приводить к принятому в js стилю camel case, а при отправке на сервер возвращать в snake case.

ts-serializable

Так же после выхода первой версии у некоторых пользователей были пожелания по функционалу. Эти пожелания реализованы в новой версии.

Если вы не знакомы с библиотекой ts-serializable, то рекомендуется сначала прочитать эту статью.

Конвертация имен свойств


По аналогии с Newtonsoft.Json были добавлены настройки сериализации. Их можно задать глобально, на один объект, или на один вызов десериализации.

Пример класса который будет десериализован из snake case в camel case, а при сериализации вернется в snake case.

import { Serializable, SnakeCaseNamingStrategy, jsonObject, jsonProperty, jsonName } from "ts-serializable";

const json = {
    first_name: "Jack",
    last_name: "Sparrow",
    date_of_birth: "1690-05-05T21:29:43.000Z",
    "very::strange::json:name": "I love jewelry"
};

@jsonObject({ namingStrategy: new SnakeCaseNamingStrategy() })
class User extends Serializable {

    @jsonProperty(String, null)
    public firstName: string | null = null;

    @jsonProperty(String, null)
    public lastName: string | null = null;

    @jsonProperty(Date, null)
    public dateOfBirth: Date | null = null;

    @jsonName("very::strange::json:name")
    @jsonProperty(String, null)
    public veryStrangePropertyName: string | null = null;

}

const user = new User().fromJSON(json);

user.firstName === json.first_name; // true
user.lastName === json.last_name; // true
user.dateOfBirth?.toISOString() === json.date_of_birth; // true
user.veryStrangePropertyName === json["very::strange::json:name"]; // true

Здесь в декоратор jsonObject передаются настройки для работы сериализации и десериализации. Так же из коробки идут KebabCaseNamingStrategy и PascalCaseNamingStrategy. Если этого не достаточно, то можно написать свой конвертер имен свойств и передать его в параметрах.

Так же можно заметить декоратор jsonName, который можно использовать на совсем специфичных именах свойств.

Указание настроек


Настройки можно задавать в разных местах:

  • Глобально. Настройки будут применяться на всех объектах, если они не переопределены в объекте или методе.
  • На объект. Настройки будут применяться на одном объекте, если они не переопределены в методе.
  • На один метод. Настройки будут применяться на одном вызове десериализации и не работают при сериализации.

// Глобальные настройки
Serializable.defaultSettings: SerializationSettings = { ...options };

// Настройки для объекта
@jsonObject(settings?: Partial<SerializationSettings>)
class User extends Serializable { ...code }

// Настройка для одной десериализации
new User().fromJSON(json: object, settings?: Partial<SerializationSettings>);

Декоратор вместо наследования


После выпуска первой версии библиотеки у некоторых пользователей возникла проблема с тем что наследование уже занято другим объектом. Реализовывать monkey patching не лучшая идея, к тому же расширения базового объекта в js ломает библиотеку react.

Но решение было найдено. Теперь объект можно расширить передав в декоратор jsonObject вторым параметром значение true:


@jsonObject(void 0, true) // расширит объект
class User {

    public fromJSON!: (json: object) => this; // успокоит typescript

    @jsonProperty(String, null)
    public firstName: string | null = null;

    @jsonProperty(String, null)
    public lastName: string | null = null;

}

Поддержка


Понравилась библиотека? Помоги сделать ее лучше и популярнее. Присылайте issue, ставьте звезды. Не бойтесь экспериментировать!