Руководство по использованию ts-reset для TypeScript

Источник: «A guide to using ts-reset for TypeScript»
Пакет ts-reset решат ряд проблем с типами в TypeScript, подобно кнопке сброса CSS, чтобы избежать ошибок, вызванных ошибками типов.

Типизация в JavaScript всегда была проблемой для разработчиков. Из-за динамической типизации разработчикам, пришедшим из языков с сильной типизацией, таких как C# или Java, сложно приспособиться к использованию JavaScript. TypeScript был создан для решения этой проблемы, но некоторые желаемые функции всё ещё отсутствуют.

Один из примеров — функция JSON.parse(). TypeScript считает, что результат этой функции имеет тип any, что создаёт ряд проблем, поскольку создаёт ложное впечатление, что с предоставленным ответом можно работать. Это может привести к возникновению ошибок. Более ожидаемым подходом было бы возвращать тип unknown, заставляя разработчика проводить дополнительную проверку.

Представляем ts-reset, кнопку сброса для TypeScript, призванную улучшить типы для распространённых JS API. В этом руководстве мы рассмотрим, как использовать и настраивать ts-reset для приложений TypeScript.

Что такое ts-reset

ts-reset — пакет с открытым исходным кодом, предоставляющий набор правил, изменяющих встроенные в TypeScript типы. ts-reset помогает улучшить типизацию TypeScript и сделать её более соответствующей ожиданиям пользователей. Он также делает код более читабельным и удобным для поддержки и позволяет избежать ошибок, вызванных ошибками типов. Этот пакет можно рассматривать как TypeScript-версию css-reset, представляющую собой список правил, сбрасывающих все стили браузера по умолчанию и устраняющих потенциальные несоответствия между различными браузерами.

Зачем нужен ts-reset

Типы по умолчанию в TypeScript для некоторых встроенных функций не самые удачные. Далее приведены два примера, в которых стандартные типы TypeScript приводят к трудноуловимым багам:

  1. .jsonfetch) и JSON.parse возвращают тип any.
  2. .filter(Boolean) выдаёт ложные значения

Использование ts-reset помогает решить эти проблемы, делая типизацию ожидаемой:

  1. .jsonfetch) и JSON.parse возвращают тип unknown.
  2. .filter(Boolean) ведёт себя так как вы ожидаете

Более подробно мы рассмотрим это в следующем разделе. А пока давайте посмотрим, как установить пакет в проект.

Настройка ts-reset в проекте

Начать работу с ts-reset очень просто. Первый шаг — установка проекта:

npm i -D @total-typescript/ts-reset

Затем создайте файл reset.d.ts в проекте со следующим кодом:

// Не добавляйте в этот файл ни каких других строк кода!
import "@total-typescript/ts-reset";

Теперь вы готовы приступить к работе! Если не нужно глобальное использование и вы предпочитаете включать его только в файл или даже в отдельную функцию, можете использовать inline подход. Для этого просто добавьте нужный хелпер в начало файла:

// Делает возвращаемый тип JSON.parse unknown
import "@total-typescript/ts-reset/json-parse";

//теперь применяется ts-reset
const result = JSON.parse("{}"); // unknown

N.B. Чтобы импорты работали, нужно убедиться, что модуль установлен на NodeNext или Node16 в tsconfig.json.

Примеры использования ts-reset

Теперь рассмотрим примеры использования пакета ts-reset для решения перечисленных ранее проблем.

Заставляем JSON.parse возвращать unknown

До ts-reset JSON.parse возвращал значение any. Это может привести к неприятным, трудноуловимым багам, потому что они отключают проверку типов значений, которые описывают:

// До ts-reset
const result = JSON.parse({}); // any

С ts-reset возвращаемый тип JSON.parse меняется на unknown. Теперь нужно либо проверить unknown, чтобы убедиться, что это правильный тип, либо преобразовать его с помощью as:

// После ts-reset
const result = JSON.parse("{}"); // unknown

Делаем, чтобы .json() возвращал unknown

Точно так же, как JSON.parse(), .json(), возвращает тип any, вводя нежелательный тип any в код приложения, что также может привести к неприятным багам:

// До ts-reset
fetch("/")
.then((res) => res.json())
.then((json) => {
console.log(json); // any
});

Заставляя res.json возвращать тип unknown, мы осознаём необходимость проверки результатов fetch, поскольку теперь мы не доверяем результату метода res.json():

// ts-reset
fetch("/")
.then((res) => res.json())
.then((json) => {
console.log(json); // unknown
});

Делаем, чтобы .filter(Boolean) фильтровал ложные значения

Поведение .filter по умолчанию ведёт себя не так, как ожидается. Учитывая набор значений в массиве со значением undefined, применение конструктора Boolean в качестве метода фильтрации удаляет все ложные значения в массиве, оставляя только не ложные значения. Однако TypeScript по-прежнему воспринимает типы как (number | undefined)[], используя исходные значения массива, а не результат новой фильтрации массива.

Для примера возьмём следующий код:

// ДО ts-reset
const filteredArray = [1, 2, undefined].filter(Boolean); // (number | undefined)[]

После применения ts-reset метод filter стал вести себя так, как и ожидается. Он действует как предикат типа на переданный массив и удаляет все ложные значения из членов массива:

// После ts-reset
import "@total-typescript/ts-reset/filter-boolean";

const filteredArray = [1, 2, undefined].filter(Boolean); // number[]

Будущие проблемы с совместимостью

Поскольку пакет ts-reset не требует настройки со стороны пользователя, у него нет проблем с совместимостью. Обратите внимание, что ts-reset предназначен для использования в коде приложения, а не в коде библиотеки. Это связано с тем, что каждое включаемое правило, будет вносить изменения в глобальную область, а это означает, что пользователи, импортирующие библиотеку, будут неосознанно использовать ts-reset.

Заключение

ts-reset — отличный пакет утилит, помогающий решить проблемы с типами в JavaScript. В этой статье мы узнали, как использовать ts-reset для улучшения типизации в TypeScript по умолчанию, чтобы сделать её более предсказуемой и защищённой от ошибок. ts-reset помогает типам TypeScript вести себя в коде так, как ожидается. Надеюсь, вы получите удовольствие от использования ts-reset для создания отличных проектов на TypeScript!

Дополнительные материалы

Предыдущая Статья

Laravel Pagination: Сохранение параметров запроса на второй странице

Следующая Статья

Использование CSS свойств object-fit и object-position