Измените рабочий процесс разработки и устраните ошибки с помощью библиотеки io-ts.
Как разработчик в Elastic, у меня было немало проблем, когда дело доходит до кодирования и декодирования типов. Одним из инструментов, который помог оптимизировать мой рабочий процесс и устранить ошибки, является библиотека io-ts, которая предоставляет систему типа времени выполнения для декодирования/кодирования ввода-вывода.
Когда я впервые начал использовать эту библиотеку, это сбивало с толку, и я изо всех сил пытался понять ее концепцию, но, привыкнув к ней, я понял, насколько она полезна при работе над крупномасштабными проектами.
Вот почему в этом посте я рассмотрю преимущества использования io-ts для лучшего кодирования и декодирования типов и почему я рекомендую рассмотреть это каждому разработчику Typescript.
Что такое типы времени выполнения и чем они отличаются от типов Typescript?
Прежде чем углубляться в особенности io-ts, важно понять, что такое типы среды выполнения и чем они отличаются от типов TypeScript.
Типы TypeScript используются только во время компиляции и поэтому ограничены в своей области. Напротив, типы времени выполнения используются во время выполнения, обеспечивая более гибкое и мощное кодирование и декодирование типов.
Существует несколько преимуществ использования типов времени выполнения с io-ts, в том числе:
- Улучшенная безопасность типов: использование io-ts обеспечивает дополнительный уровень безопасности при кодировании и декодировании данных, предотвращая обработку неожиданных или недопустимых значений.
- Повышенная гибкость. Типы среды выполнения допускают более сложные определения типов, чем типы TypeScript, что может быть полезно при работе со сложными структурами данных.
- Простая интеграция с внешними источниками данных. С помощью io-ts легко определить собственные кодеки для интеграции с внешними источниками данных, такими как API или базы данных.
- Более информативные сообщения об ошибках. При возникновении ошибки во время кодирования или декодирования io-ts предоставляет подробные сообщения об ошибках, которые упрощают выявление и устранение проблемы.
Однако есть и некоторые потенциальные недостатки использования io-ts, в том числе:
- Повышенная сложность. С добавленной гибкостью типов среды выполнения возникает дополнительная сложность, которая может обескуражить разработчиков, не знакомых с библиотекой.
- Накладные расходы. Использование типов среды выполнения может привести к дополнительным затратам во время кодирования и декодирования, что в некоторых случаях может повлиять на производительность.
- Кривая обучения. Несмотря на то, что io-ts хорошо задокументирована, для освоения библиотеки по-прежнему требуется обучение.
Внедрение систем типа времени выполнения с помощью io-ts
Несмотря на потенциальные недостатки, я считаю, что преимущества использования io-ts намного перевешивают недостатки. Чтобы продемонстрировать, как реализовать системы времени выполнения с помощью io-ts, я рассмотрю пример кодирования и декодирования данных для вымышленного приложения списка дел.
Во-первых, мы определим типы среды выполнения для элементов нашего списка дел:
import * as t from 'io-ts'; const todoRT = t.type({ id: t.number, title: t.string, completed: t.boolean }); // 🤩 It is possible to derive a TS type from the runtime type definition type Todo = t.TypeOf<typeof todoRT>; const todoListRT = t.array(todoRT);
Определив эти типы среды выполнения, мы теперь можем использовать их для кодирования и декодирования данных. Например, чтобы декодировать данные JSON в элементы нашего списка дел, мы можем использовать следующий код:
import { pipe } from 'fp-ts/lib/function'; import * as E from 'fp-ts/lib/Either'; import * as D from 'io-ts/lib/Decoder'; const decodeTodos = (input: string) => pipe( D.parse(input, todoListRT.decode), E.getOrElse(() => []) );
Используя функцию decodeTodos
, мы можем легко декодировать строку JSON в массив элементов списка дел со встроенной обработкой ошибок.
Это базовый пример, но io-ts поставляется с утилитами, которые позволяют создавать более сложные типы среды выполнения!
Давайте теперь посмотрим на реальный пример создания общего типа среды выполнения для кодирования/декодирования полезной нагрузки ответа из CRUD API списков дел.
Использование типа времени выполнения Todo с API
Теперь, когда мы создали тип среды выполнения todoRT
, давайте рассмотрим, как мы можем использовать его в более сложном примере. Теперь мы увидим, как кодировать полезную нагрузку ответа на запрос GET в бэкэнде, используя тип среды выполнения todoRT
, и как декодировать ответ на клиенте.
Допустим, у нас есть конечная точка сервера, которая возвращает список задач в следующем формате:
interface Todo { id: number; title: string; description: string; completed: boolean; createdAt: string; updatedAt: string; } type TodoList = Todo[];
Как мы видели ранее, мы можем получить тип Typescript из определения типа времени выполнения, поэтому нам не нужно будет вручную создавать тип, определенный выше.
В бэкэнде мы можем использовать тип времени выполнения todoRT для проверки полезной нагрузки ответа перед отправкой обратно клиенту:
import * as t from 'io-ts'; import { isLeft } from "fp-ts/Either"; const todoRT = t.type({ id: t.number, title: t.string, description: t.string, completed: t.boolean, createdAt: t.string, updatedAt: t.string }); const todoListRT = t.array(todoRT); type TodoList = t.TypeOf<typeof todoListRT>; router.get('/api/todos', (req: Request, res: Response) => { // Fetch todos from the database const todos: TodoList = fetchTodosFromDb(); // Validate the todos using the runtime type const result = todoListRT.decode(todos); if (isLeft(result)) { // Handle validation error res.status(500).send({ message: 'Invalid todo payload' }); return; } // Return the validated todos res.status(200).send(result.right); })
Функция
isLeft
из библиотеки fp-ts/Either принимает значениеEither
и возвращает логическое значение, указывающее, представляет ли оно левое значение или нет. Значение Left представляет случай сбоя или ошибки, а значениеRight
представляет случай успеха. Поэтому функциюisLeft
можно использовать для проверки того, не привела ли операция к ошибке.
В клиенте мы можем использовать тип среды выполнения todoListRT
для декодирования полезной нагрузки ответа перед ее использованием в нашем приложении:
async function getTodos() { const response = await fetch('/api/todos'); const todos: TodoList = await response.json(); // Validate the response using the runtime type const result = todoListRT.decode(todos); if (isLeft(result)) { // Handle validation error throw new Error('Invalid todo payload'); } return result.right; }
Сначала мы получаем ответ от сервера, а затем используем тип среды выполнения todoListRT
для декодирования полезной нагрузки ответа. Если полезная нагрузка недействительна, мы выдаем ошибку. В противном случае мы возвращаем проверенные задачи.
Использование типов среды выполнения таким образом может увеличить нагрузку на ваше приложение, но оно того стоит, поскольку оно также может обеспечить лучшую безопасность типов и проверку данных вашего приложения.
Заключение
Я искренне верю, что мы всегда должны заботиться о проверке нашего ввода/вывода после передачи данных, и io-ts до сих пор был для меня отличным DX, я бы порекомендовал любому коллеге попробовать его в стороннем проекте или на сложная платформа, чтобы увидеть преимущества и структуру, которые она привносит в проект!
Дополнительные материалы на PlainEnglish.io.
Подпишитесь на нашу бесплатную еженедельную рассылку новостей. Подпишитесь на нас в Twitter, LinkedIn, YouTube и Discord .