Представляю вашему вниманию перевод статьи "Working With TypeScript: A Practical Guide for Developers". TypeScript — это популярный статический типизатор (static type checker) или типизированное надмножество (typed superset) для JavaScript, инструмент, разработанный Microsoft и добавляющий систему типов к гибкости и динамическим возможностям JavaScript. TypeScript развивается как проект с открытым исходным кодом, распространяется под лицензией Apache 2.0, имеет очень активное и высокопрофессиональное сообщество, а также огромное влияние на экосистему JavaScript. Для того, чтобы начать работу с TypeScript, нужно либо установить специальный интерфейс командной строки (command line interface, CLI), либо воспользоваться официальной онлайн-песочницей или другим похожим инструментом. Для выполнения кода мы будем использовать Node.js. Устанавливаем его, если он еще не установлен на вашей машине, инициализируем новый Node.js-проект и устанавливаем транспилятор TypeScript: Это установит tsc (компилятор TypeScript) для текущего проекта. Для того, чтобы проверить установку, в директории проекта создаем файл index.ts следующего содержания: Затем используем транспилятор для преобразования кода, содержащегося в этом файле, в JavaScript: Наконец, выполняем скомпилированный код с помощью команды node: В данном случае транспилятор не делает ничего, кроме копирования кода из одного файла в другой, но это позволяет убедиться, что все установлено и работает правильно. Обратите внимание: версии TypeScript могут сильно отличаться друг от друга, даже если речь идет о минорных релизах. Поэтому TypeScript лучше устанавливать локально и выполнять с помощью npx, вместо того, чтобы полагаться на глобальную версию. Для определения TypeScript-проекта внутри Node.js-проекта, необходимо создать файл tsconfig.json. Присутствие данного файла в директории свидетельствует о том, что мы имеем дело с TypeScript-проектом. tsconfig.json содержит определенное количество настроек, которые влияют на поведение транспилятора, например, на то, какие файлы следует игнорировать, какой файл является целью компиляции, какие типы импортируются и т.д. Вы легко можете настроить TypeScript с помощью следующей команды: Сгенерированный tsconfig.json содержит почти все возможные настройки с кратким описанием каждой из них. К счастью, данный файл содержит хорошие настройки по умолчанию, так что вы можете удалить большую часть закомментированных опций. Мы еще вернемся к настройкам TypeScript, а сейчас давайте писать код. Каждая возможность TypeScript подробно рассматривается в "Карманной книге по TypeScript". Мы сосредоточимся на практической составляющей некоторых из них. Я постараюсь пролить свет на некоторые возможности, которые часто упускаются из вида в литературе, посвященной TypeScript. Ключевая идея TypeScript заключается в контроле за динамической природой и гибкостью JavaScript с помощью типов. Давайте рассмотрим эту идею на практике. В директории проекта создаем файл test.js следующего содержания: Выполняем данный код: В терминале мы увидим thirty two1 без каких-либо предупреждений об очевидной некорректности вывода. Ничего нового: обычное поведение JavaScript. Но что если мы хотим обеспечить, чтобы функция addOne() принимала только числа? Вы можете добавить в код проверку типа переданного значения с помощью оператора typeof или же вы можете использовать TypeScript, который привнесет в процесс компиляции кода некоторые ограничения. Заменим содержимое созданного нами ранее index.ts следующим кодом: Обратите внимание, что мы ограничили принимаемый функцией аргумент и возвращаемое функцией значение типом number. Преобразуем файл: Попытка преобразования проваливается: Таким образом, определение типов помогает избежать совершения ошибок, таких как передача в функцию аругментов неправильного типа. string и number — это лишь два из основных типов, поддерживаемых TypeScript. TypeScript поддерживает все примитивные значения JavaScript, включая boolean и symbol. Кроме того, TypeScript определяет несколько собственных типов, которые не имеют соответствия в JavaScript, но являются очень полезными с точки зрения используемой в данной экосистеме методологии: TypeScript поддерживает несколько типов множеств (обычные массивы, ассоциативные массивы — карты или мапы, кортежи), обеспечивая первоклассную поддержку композиции. Карты, как правило, используются для определения связи между ключами и значениями для представления специфичных для приложения данных: Векторы — это последовательная индексированная структура данных, содержащая фиксированные типы для всех элементов. JavaScript не поддерживает данную возможность, но TypeScript позволяет разработчикам эмулировать эту концепцию: Кортежи также являются индексированной структорой данных, но типы элементов могут различаться в зависимости от их позиции: Другим способом создания композиции типов являются объединения, которые бывают полезны в случаях, когда принимаемый функцией аргумент может иметь один из нескольких типов. Предположим, что мы хотим создать функцию, возвращающую адрес пользователя на основе переданного объекта или строки. Прежде всего, давайте установим node-fetch, чтобы иметь возможность использовать функцию fetch в Node.js: Затем с помощью typeof осуществляем разделение типов: Здесь мы в явном виде реализовали предохранитель типов. К слову, кортежи и объединения можно использовать совместно: Можно определять размер и тип каждого элемента массива: Предохранители типов — это выражения, выполняющие проверки во время выполнения кода, результат которых может быть использован системой типов для сужения (narrow) области (scope) проверяемого аргумента. Одним из предохранителей является оператор typeof, который мы использовали в предыдущем примере для сужения области аргумента user. Существуют и другие предохранители, такие как instanceof, !== и in, полный список можно найти в документации. Для случаев, когда система типов не может сделать правильный вывод о типе в текущем контексте, мы можем определить пользовательский предохранитель типа через предикат (типизированная функция, возвращающая логическое значение): Пользовательские предохранители находятся под полным контролем разработчика, TypeScript не имеет возможности убедиться в их корректности. Весьма распространенным случаем использования пользовательских предохранителей является влидация внешних данных с помощью JSON-схемы, предоставляемой сторонней библиотекой, такой как Ajv. Обычно, это происходит в веб-приложениях, где тело запроса имеет тип unknown (или any в зависимости от используемого фреймворка), и мы хотим проверить его перед использованием: В основе данного механизма лежит синхронизация JSON-схемы с типом. Если мы изменим тип, но не изменим схему, то вполне можем получить неожиданное сужение типа. В следующем разделе мы узнаем, как обеспечить автоматическую синхронизацию между схемой и типом. Объединения с общим литеральным полем называются исключающими. При работе с такими типами TypeScript предоставляет неявный предохраитель, позволяя избежать его создания в явном виде: В функции getFirstProject() TypeScript сужает область аргумента без помощи предиката. Попытка получить доступ к массиву projects в первой ветке (блоке if) закончится ошибкой типа. Как было отмечено ранее, в случае с пользовательскими предохранителями, корректность возвращаемого результата обеспечивается разработчиком. При наличии ошибки в предикате, система типов может получить неверную информацию. Рассмотрим пример: Данный предикат всегда возвращает true, позволяя типизатору сузить тип к тому, чем он на самом деле не является: Существует несколько библиотек, которые позволяют обеспечить автоматическую синхронизацию между валидацией во время выполнения и соответствующим типом. Одним из самых популярных решений является runtypes, однако мы будем использовать io-ts и fp-ts. Суть данного подхода состоит в том, что мы определяем форму (или фигуру) типа с помощью примитивов, предоставляемых io-ts; эта форма называется декодером (decoder); мы используем ее для проверки данных, которым мы по какой-либо причине не доверяем: Поведение транспилятора можно настраивать с помощью файла tsconfig.json, находящегося в корне проекта. Данный файл содержит набор ключей и значений, отвечающих за 3 вещи: TypeScript может преобразовывать код в ES3 и поддерживает несколько форматов модулей (CommonJS, SystemJS и др.). Точные настройки зависят от среды выполнения кода. Например, если вашей целью является Node.js 10, вы можете транспилировать код в ES2015 и использовать CommonJS в качестве стратегии разрешения модулей. Если вы используете последнюю версию Node.js, например, 14 или 15, тогда можете указать в качестве цели ESNext или ES2020 и использовать модульную стратегию ESNext. Наконец, если вашей целью является браузер и вы не используете сборщик модулей, такой как webpack или parcel, то можете использовать UMD. К счастью, команда TypeScript разработала хороший набор пресетов, которые вы можете просто импортировать в свой tsconfig.json: Среди наиболее важных настроек, можно отметить следующее: Надеюсь, данная статья позволила вам получить общее предствления о возможностях, предоставляемых TypeScript, а также о том, почему использование TypeScript в дополнение к JavaScript в настоящее время фактически является стандартом веб-разработки. Система типов TypeScript не является идеальной, но это лучшее, что мы имеет на сегодняшний день. Облачные серверы от Маклауд отлично подходят для сайтов с JavaScript. Зарегистрируйтесь по ссылке выше или кликнув на баннер и получите 10% скидку на первый месяц аренды сервера любой конфигурации!