Можно ли использовать typescript в js файлах
Я — большой любитель TypeScript. По возможности я стараюсь использовать этот язык в своих проектах. TypeScript даёт разработчику отчёты об ошибках и проверку типов в JavaScript и TypeScript-коде. Кроме того, тот, кто пишет на TypeScript, может пользоваться удобными возможностями по автозавершению кода, может, быстро и надёжно, выполнять рефакторинг. TypeScript — это первая линия обороны от ошибок в коде. Ещё одна сильная сторона этого языка заключается в том, что он позволяет, при написании программ, пользоваться самыми свежими возможностями JavaScript. При этом то, что получается при преобразовании TypeScript-кода в JavaScript, будет поддерживаться всеми браузерами. Это очень приятно.
Правда, не все фронтенд-проекты предусматривают применение TypeScript. Что если можно было бы пользоваться возможностями TypeScript, но при этом не переводить на него весь проект (и всю команду), и не добавлять в конвейер сборки проекта новый инструмент? Это возможно благодаря VS Code и JSDoc.
Типизация кода с использованием JSDoc
Только что мы поговорили о том, как включать TS-проверку на уровне файлов. Это даёт базовые возможности по проверке типов. Их можно расширить, описывая типы с помощью комментариев формата JSDoc.
Уточнение типов с помощью typescript-eslint
ESLint в Etsy активно отлавливает всевозможные плохие паттерны, помогает отказаться от старого кода и делает комментарии к PR информативными. Миграция на TypeScript означала появление множества новых практик. Нужно было подумать и написать для них правила линтинга.
Если что-то важно, то мы стараемся написать для этого правило ESLint. Кроме того, линтинг проверяет, насколько точно тип соответствует тому, что он описывает. Поговорим об этом подробнее.
Представьте функцию, принимающую имя HTML-тега и возвращающую HTML-элемент. Её аргумент — любая строка. Но если функция использует строку, чтобы создать элемент, то неплохо было бы гарантировать, что она совпадает с названием существующего в HTML элемента:
С более конкретными типами разработчикам проще использовать функцию правильно:
Проект typescript-eslint предоставил специфичные для TypeScript правила. К примеру, ban-types предостерегает от обобщённого типа Element в пользу более определённого HTMLElement.
Кроме того, мы приняли несколько спорное решение не допускать в нашей кодовой базе утверждения non-null и утверждения типов:
Первое утверждение сообщает TypeScript, что нечто — это не null, когда TypeScript полагает, что null допустим.
Второе позволяет рассматривать что-либо как любой тип на своё усмотрение.
Эти особенности позволяют переопределить то, как TypeScript вообще понимает тип. Во многих случаях они подразумевают более глубокие проблемы типа. Отказавшись от них, мы заставляем типы быть конкретнее. К примеру, "as" допустимо для преобразования Element в HTMLElement, но, вероятно, вы изначально хотели использовать HTMLElement.
В самом TypeScript нет возможности отключить подобное, но линтинг выявляет и предотвращает развёртывание таких конструкций. Это не значит, что шаблоны однозначно плохи. Но линтинг — это разумный выход из положения. Если as очень, очень нужно — просто добавьте исключение:
Поддержка TypeScript нашими инструментами
Мы хотели, чтобы, до того как инженеры начнут писать на новом языке, он поддерживался в наших инструментах, а все основные библиотеки имели удобные, хорошо определённые типы. Заставлять людей писать типы для обычных утилит, пока они учат новый язык и не отстают от плана команды, — хороший способ вызвать неприятие.
Зависимости без типов в файле TypeScript затрудняют работу с кодом и приводят к ошибкам типов, хотя TypeScript пытается определить типы в файле, который не относится к TypeScript, если это не удаётся, язык возвращает тип “any”. Говоря коротко, если инженер пишет на TypeScript, ему нужна уверенность, что язык отлавливает ошибки типов.
Как преобразовать приложение JavaScript для поддержки TypeScript.
Стратегия внедрения
Множество файлов JavaScript превращаются в TypeScript заменой расширения. Но, чтобы TypeScript полностью понимал файлы, многие из них должны быть аннотированы типами. Даже если TypeScript прекрасно понимает файл, благодаря хорошо определённым типам разработчики выигрывают время. Кроме того, проверка типов TypeScript лучше работает с более строгими типами. Чтобы мигрировать на TS, нужно было ответить на эти вопросы:
Насколько строгим должен быть TypeScript?
Какой код мы хотим перенести?
Насколько конкретными должны быть типы?
Миграция на новый язык требует больших усилий, и если мы имеем дело с TypeScript, то можем использовать все преимущества системы типов языка. Мы решили, что приоритет — строгость, поскольку строгий TypeScript предотвращает распространённые ошибки.
Перенос каждого файла отдельно — это трата времени, но предоставить типы новым и часто обновляемым частям сайта было важно. Хотелось, чтобы типы были максимально полезными и простыми в использовании.
Как заботиться о сборке и упаковке
Давайте просто рассмотрим изменения до и после в нашем файле конфигурации сборки.
Вот так наш файл .travis выглядел раньше (упрощенная версия):
И вот как он выглядел после этого:
Обратите внимание, что большинство изменений касается «упаковки» файла tar.xz и выполнения команды build-dist перед доступом к папке dist .
▍Типизация функций
Начать типизацию кода средствами JSDoc можно с описания того, что функции принимают на вход:
После этого редактор сможет выдавать подсказки по типам.
Подсказка по типу значения, принимаемого функцией
Этот метод хорошо подходит для простых типов, но что если разработчику нужно описывать собственные типы? Сделать это можно с помощью тега @typedef . Рекомендую помещать описания типов в начале файла. Это облегчит обнаружение таких описаний в ходе работы:
Такие описания можно использовать там, где это нужно:
Ещё один вариант применения этой методики заключается в перемещении объявлений типов в особые файлы. Скажем, такой файл может называться main.d.ts .
Эти типы потом можно использовать в JavaScript:
Установить машинописный текст
запустить: npm install typescript .
Как мы изучали TS
Мы искали команды, собиравшиеся начать новые проекты с относительно гибкими сроками, и спрашивали, интересен ли им TypeScript. Пока они работали, наша единственная задача состояла в том, чтобы просматривать их PR, писать необходимые типы модулей и по мере обучения работать с ними.
За это время мы доработали типы и написали документацию, специально предназначенную для сложного кода. На TS писали всего несколько инженеров, поэтому получить от них обратную связь и разобраться в проблемах было легко.
Первые команды во многом определили правила линтинга и помогли убедиться, что документация понятна и полезна. Также мы получили время, необходимое для завершения технических моментов миграции, таких как добавление типов в API.
▍Вариант №1. Настройки VS Code (глобальная проверка)
Первый способ использования TypeScript (TS) в проектах, написанных на обычном JavaScript (JS), заключается в том, чтобы применять TS для проверки всех JS-файлов. Делается это посредством включения одного глобального параметра VS Code. Этот параметр можно включить в настройках пользователя или рабочего пространства:
Если вы из тех, кто предпочитает пользоваться графическим интерфейсом, то включить это можно так, как показано ниже.
Включение проверки JS-кода средствами TypeScript
Обучение команд
Почувствовав, что устранено большинство недочётов, мы брали в работу любую проявившую интерес команду. Чтобы подготовить людей к TypeScript, мы нашли курс от ExecuteProgram, который, по нашему мнению, хорошо подходит для этого и попросили их сначала пройти обучение.
Курс должна была пройти вся команда, кроме тех, кто имел аналогичный опыт. А ещё мы связались с Дэном Вандеркамом, автором книги Effective TypeScript, чтобы узнать, будет ли ему интересно прочитать внутренний доклад. Я разработал виртуальные значки, их мы выдавали в середине и в конце курса, чтобы поддержать мотивацию и проследить скорость изучения TypeScript.
Новым командам мы предложили выделить время для переноса их JS-файлов. И обнаружили, что перенос знакомого файла — отличный способ научиться TypeScript. Это практичный способ работать с типами, которые можно сразу использовать в других местах.
От сложных инструментов автоматической миграции (как в AirBnB) мы отказались отчасти потому, что они лишают некоторых возможностей обучения. Кроме того, инженер с небольшим знанием контекста перенесёт файл эффективнее, чем скрипт.
Профилирование и новые впечатления от разработки
Важной частью внедрения было пристальное внимание к жалобам инженеров. Хотя мы только начали работу по миграции, несколько человек отметили, что, наведя курсор на переменную, информации о типе они ждали полминуты. Проблема становилась ещё загадочнее, ведь проверка типов во всех файлах выполнялась меньше минуты.
Но нам посчастливилось встретиться с мейнтейнерами TypeScript, заинтересованными в успехе языка в уникальной кодовой базе Etsy. Проблемы с редактором их удивили. А выяснив, что TypeScript потребовалось почти 10 полных минут, чтобы проверить весь код, они удивились ещё больше. После обсуждений разработчики TS указали на совсем новую функцию отслеживания производительности. Оказалось, что TS пытался проверить тип немигрировавшего файла. Ниже вы видите трассировку, где ширина — это время.
Типы безупречно работали со всем кодом, но в ещё не мигрированных частях кода возникали проблемы. Они и приводили к бесконечному циклу. Когда в местах с таким циклом кто-то открывал файл. А когда мы запускали полную проверку типов, TypeScript попадал в бесконечный цикл, тратил много времени в попытке разобраться, сдавался и выдавал ошибку типа.
Тот самый тип вызывал проблемы и в других местах: после исправления проверка всего кода ускорилась в три раза, а использование памяти сократилось на 1 Гб. Посмотрите на трассировки и графики:
Ошибки компиляции TypeScript
Одним из преимуществ TypeScript является то, что он может автоматически обнаруживать ошибки в вашем коде, если типы не совпадают. Например, представьте, что в приведенном выше примере, для параметра name мы вызываем функцию .trim(). Если мы передадим переменную любого другого типа, это может привести к тому, что наш код вызовет ошибку при воспроизведении в браузере. Давайте посмотрим на наш обновленный пример, неправильно передав массив в функцию:
Это приведет к следующей ошибке TypeScript при запуске команды tsc index.ts:
Учебные ресурсы
Вот несколько ресурсов, которые я считаю полезными:
TypeScript’s Handbook — это фантастический ресурс, если вы новичок.
Я многое узнал о языке и его внедрении из книги Дэна Вандеркама Effective TypeScript.
Вики о производительности проекта TypeScript — это кладезь полезных советов по производительности среды TypeScript.
Если вы хотите действительно хорошо писать сложные типы для странных библиотек, репозиторий Type-challenges — отличный способ получить опыт.
Продолжить изучение технологий веб-разработки вы сможете на наших курсах:
Эта статья покажет вам, как быстро начать работать с TypeScript, и мы обсудим плюсы и минусы использования TS. TypeScript - это расширенный набор JavaScript и стандарта TC39. С помощью TS мы можем определять как простые, так и сложные статические типы для переменных в нашем коде.
TypeScript - это просто JavaScript с необязательным добавлением типов для ваших переменных. Вы можете писать в современном синтаксисе JavaScript (ES2015+) и использовать TypeScript, после чего с помощью компилятора преобразовывать TypeScript(.ts) в JavaScript(.js), и также при необходимости скомпилировать JavaScript с поддержкой предыдущих версий, таких как ES5.
Обратите внимание, что если вы используете require() или import/export, вам все равно нужно будет использовать сборщик для браузера, такой как Webpack, Rollup или SystemJS.
Как мне позаботиться о линтинге?
Доступно несколько вариантов линтинга.
Первым решением, которое мы использовали, было tsfmt, но позже мы отказались от него, потому что оно требует от вас поддержки двух отдельных конфигураций для вашего проекта (для TypeScript через sfmt и отдельный для JavaScript, с помощью eslint ). Проект также выглядит устаревшим.
Затем мы нашли TSLint, который перенаправил нас на плагин eslint для TypeScript. Затем мы настроили его следующим образом:
Это был наш eslintrc.js :
Который мы настроили для запуска с помощью команды lint-fix в нашем package.json который выглядит следующим образом:
Комплексный подход - преобразование полной кодовой базы из JS в TS
Этот вариант требует полной перезаписи кода JavaScript на TypeScript.
Я бы порекомендовал сделать это в качестве последнего шага в процессе миграции TS, поскольку он требует полной переписывания приложения и глубоких знаний TypeScript и его функций.
Вы можете выполнить такую перезапись (это долгий процесс) следующим образом:
Имейте в виду, что есть автоматизированные инструменты, призванные облегчить этот процесс, например ts-migrate от команды Airbnb.
Он решает эту проблему с другой точки зрения и конвертирует все файлы в TypeScript. Это также позволяет постепенно улучшать (как указано в шагах выше), в то время как вся кодовая база является TypeScript с первого дня.
▍Вариант №2. Использование файла jsconfig.json (глобальная проверка)
Ещё один вариант включения глобальной проверки JS-кода средствами TS заключается в использовании файла jsconfig.json . Если такой файл имеется, настройки, заданные в нём, переопределят настройки, заданные в VS Code.
Hello world в TypeScript
В качестве примера, вот шаги, которые вам нужно предпринять, чтобы написать свое первое приложение TypeScript:
- установить TypeScript с помощью npm i typescript
- создайте папку с именем example и cd (в вашем терминале)
- создать файл с именем hello.world.ts
- напишите в нем следующий код:
а затем сохраните его.
5. запустите команду tsc для запуска компилятора TypeScript в текущей папке.
6. обратите внимание, что у вас есть файл hello.js , который теперь можно запустить:)
7. запустить node ./hello.js
Как я могу использовать TypeScript в проекте JavaScript?
Есть несколько стратегий для выполнения этой «миграции» (с точки зрения компании и кода). Я перечислил их ниже по их «стоимости» и по степени ценности.
Я бы посоветовал начать с «поддержки приложений TS» и двигаться дальше после того, как вы доказали ценность для своей команды разработчиков.
Типы и API
Мы хотели, чтобы на TypeScript разработчики писали эффективный код. Нужно было гарантировать, что типы предоставлены в большей части среды разработки. На первый взгляд это означает добавить типы в многократно используемые компоненты проектирования, вспомогательные утилиты и другой общий код. Но в идеале собственные типы должны иметь любые необходимые разработчику данные.
Почти все данные на сайте Etsy проходят через API на PHP, а значит, предоставив типы там, мы быстро получили бы покрытие подавляющей части кода. Чтобы упростить выполнение запроса, для каждой конечной точки мы создаём конфигурации на PHP и JavaScript и используем лёгкую обёртку вокруг запроса — EtsyFetch:
А чтобы превратить конечные точки в спецификации OpenAPI, мы воспользовались наработками собственного API для разработчиков. Спецификации OpenAPI — это стандартизированные способы описания конечных точек API в формате JSON.
Потратив много времени на генератор спецификаций OpenAPI, работающий со всеми внутренними конечными точками, при помощи openapi-typescript мы преобразовали эти спецификации в типы TypeScript.
Существующие вызовы к EtsyFetch теперь имели строгие типы “из коробки”, не требовалось никаких изменений. А если обновить API и сломать код на клиенте, сработает проверка типов и сломанный код не попадает в продакшн.
Типизация API также открыла возможность использовать его как единый источник истины между бэкендом и браузером. Гарантировать, что эмодзи с флагом у нас есть для всех локалей API, теперь можно было так:
И самое приятное: ни одна из этих функций не требовала изменений в рабочих процессах инженеров по продуктам. Используя уже знакомый паттерн, люди получали типы в довесок.
Устанавливаем TypeScript
Сначала установите TypeScript, используя npm:
или с помощью yarn:
После глобальной установки вам будет доступна команда в терминале tsc.
Что такое машинописный текст?
TypeScript - это типизированное надмножество JavaScript, которое компилируется в обычный JavaScript.
TypeScript состоит из нескольких частей. Первый - это язык TypeScript - это новый язык, содержащий все функции JavaScript. Ознакомьтесь со спецификациями для получения дополнительной информации.
Второй - компилятор TypeScript tsc (механизм системы типов), это механизм компиляции, который создает ts-файлы и выдает js-файлы.
Настройка рабочей среды
Внедрение по командам
Мы должны были предотвратить использование TypeScript отдельными инженерами до полной готовности команды. TypeScript — действительно классный язык, и люди стремились попробовать его, особенно увидев, что он используется в нашем коде. Чтобы предотвратить преждевременное использование языка, мы написали для коммитов git простой хук, который запрещал изменения TypeScript от пользователей вне доверенного списка. Когда команда была готова, она добавлялась в этот список.
Дополнительные расширения файлов TypeScript
В дополнение к файлам с расширением .ts вы также можете использовать расшируение .d.ts для добавления типов в уже существующие библиотеки JavasScript или файлы .tsx для написания синтаксиса JSX в TypeScript для приложений с React.
Я люблю писать код. И я хочу быть в этом действительно хорош. Но почему-то написание JavaScript никогда не было моей сильной стороной.
Сколько бы я ни практиковался, в продакшене продолжали появляться одни и те же ошибки: исключения cannot read property <> of undefined , знаменитая строка [Object object] и даже вызовы функций с недопустимым количеством параметров.
Более того, большинство кодовых баз, над которыми я работал, были действительно большими JavaScript-базами. Вот хорошая диаграмма того, как я себя чувствовал:
Мы можем сделать намного лучше!
В этом посте я не буду объяснять, почему TypeScript великолепен (и это так), и сосредоточусь на задачах, которые вам нужно выполнить, если вы хотите перенести свой обычный проект JavaScript в смешанный проект TypeScript.
К концу поста вы станете более счастливым человеком и сможете ответить на следующие вопросы:
- Как я могу добавить типы в свой проект JavaScript?
- Что такое TypeScript?
- Как я могу использовать TypeScript в проекте JavaScript?
- Что нужно сделать, чтобы преобразовать приложение JavaScript для поддержки TypeScript?
- Как я могу позаботиться о сборке и упаковке?
- Как мне позаботиться о линтинге?
- Как я могу «продать» TypeScript моей организации и разработчикам?
Переход на TypeScript
Если вы решили перевести на TypeScript JavaScript-проект, в некоторых частях которого используется TypeScript, можно просто переименовать jsconfig.json в tsconfig.json и включить в нём параметр allowJs :
После этого можно приступать к переименованию *.js -файлов в *.ts -файлы и к типизации кода этих файлов. Процесс перевода проекта на TypeScript может происходить постепенно.
Строгий TS
Наше решение не было идеальным:
Большей части кода JS потребовались аннотации типов.
Подход требовал переноса файл за файлом, адаптации команды за командой.
В попытке преобразовать всё сразу со строгим TS возникло много требующих решения проблем.
Мы сосредоточились на типизации активно изменяемых областей сайта и расширениями JS/TS чётко разграничили файлы с надёжными и ненадёжными типами. Одновременная миграция затрудняет логистическое совершенствование существующих типов, особенно в монорепозитории. Возникли такие вопросы:
Если импортировать файл TypeScript с существующей, но отключённой ошибкой типа, нужно ли исправлять ошибку?
Означает ли это, что типы файла должны быть другими, чтобы учесть потенциальные проблемы с этой зависимостью?
Кому она принадлежит, безопасно ли её редактировать?
Как выяснила команда, каждая устранённая двусмысленность позволяет инженеру внести улучшения самостоятельно. При инкрементной миграции надёжные типы может иметь любой файл .ts или .tsx.
Подход «маленький шаг для человека» - добавление поддержки TS для существующих приложений
Мое первое предложение - создать смесь двух языков в одном проекте, а затем написать весь «будущий» код на TypeScript.
Комбинация двух языков в одном проекте сначала звучит ужасно, но работает достаточно хорошо, поскольку TS был построен для постепенного использования. Сначала его можно использовать как JS с файлами .ts и странными строками импорта.
В этой стратегии мы будем компилировать перенесенные файлы TypeScript и просто копировать файлы JavaScript в папку вывода.
Огромное преимущество этого подхода заключается в том, что он позволяет команде разработчиков (и вам) постепенно обучаться языку и его функциям. Это также дает вам практический опыт и понимание его плюсов и минусов.
Я настоятельно рекомендую начать с этого шага, а затем повторить его вместе со своей командой, прежде чем двигаться дальше. Чтобы быстро узнать, как это сделать, прокрутите вниз до раздела The steps to convert a javascript application to support typescript .
Поддержка библиотек
TypeScript уже имеет указания типов для стандартной библиотеки Node.js, так что вы можете пользоваться проверками и дополнением практически всех её функций из коробки. Некоторые сторонние библиотеки также имеют файл с указанием типов(как правило — это файл с расширением d.ts ) в своих npm пакетах. Добавление @ts-check для вашего проекта будет так же учитывать типы импортированных из таких библиотек функций и объектов.
Скелет - шаг в будущее
Я предполагаю, что большинство разработчиков «ленивы» и обычно запускают свое приложение с копирования из каркаса (который обычно содержит журналы, показатели, конфигурацию и так далее).
Этот шаг поможет вам проложить свой путь в светлое будущее, создав «официальный» каркас вашей компании. Это будет 100% TS, и устаревший каркас JS, если он существует.
Этот стартовый узел typescript - действительно хороший первый проект для начала.
Как «продать» машинописный текст вашей команде разработчиков
Я считаю, что одним из наиболее важных аспектов внедрения TypeScript в вашу организацию является «pitch» и то, как вы представляете его своей команде разработчиков.
Вот презентация, которую мы представили внутри компании, которая вращалась вокруг следующих тем:
- Объясните, почему мы считаем TypeScript крутым
- Что такое TypeScript
- Некоторые базовые примеры кода. Главное в этой части - не «обучать» 100% TypeScript, поскольку люди будут делать это сами. Вместо этого дайте людям почувствовать, что они могут читать и писать TypeScript и что кривая обучения не так уж и сложна.
- Расширенные примеры кода, такие как типы Union и алгебраические типы данных, которые предоставляют огромные возможности JS-разработчику. Это настоящие удовольствия, помимо типизированного языка и компилятора, который привлечет к нему ваших разработчиков.
- Как начать пользоваться. Поощряйте людей загрузить IDE vs-code и добавить аннотацию ( // @ ts-check), чтобы они могли начать видеть волшебство! В нашей компании мы заранее подготовили некоторые действительно крутые ошибки, которые выявляют ts-check , и мы провели живую демонстрацию (2-3 минуты), чтобы показать, насколько быстро компилятор TypeScript может помочь им с помощью документов JS с аннотациями типов или ts-check ).
- Погрузитесь в некоторые особенности. Объясните файлы ts.d и @types packages которые являются одними из вещей, которые вы действительно встретите в самом начале TypeScript программы.
- Живой пиар от вашей работы. Мы показали PR, который мы создали на раннем этапе, и призвали людей просмотреть его и попробовать на себе.
- Поделитесь классными ресурсами. В сети много контента, и сложно отличить хорошее от плохого. Копайте глубже и постарайтесь найти качественный контент об инструментах, которые вы используете и которые вам нужны.
- Создайте публичный пул-реквест. Я рекомендую попытаться получить как можно больше поддержки для его утверждения.
10. Создайте в своей организации положительный отзыв об изменениях!
Я настоятельно рекомендую настроить этот список в соответствии с вашей командой, стандартами и ограничениями по времени.
▍Типизация обычного кода
Вышеприведённые примеры решают задачу типизацию входных и выходных значений функций. Нечто подобное можно делать и с помощью встроенных в код JSDoc-комментариев.
Типизация обычной переменной
Как я могу добавить типы в свой проект JavaScript?
Vanilla JavaScript в настоящее время не поддерживает типы, поэтому для этого нам нужна какая-то абстракция поверх JavaScript.
Некоторые распространенные абстракции используют статическую проверку типов Facebook под названием flow и язык Microsoft под названием typescript .
Конфигурационный файл Typescript
Добавьте файл конфигурации TypeScript, который можно создать с помощью команды tsc --init в вашем интерфейсе командной строки.
Вот пример того, как выглядела наша первоначальная конфигурация:
Несколько замечаний выше:
- Мы читаем все файлы в каталоге src или test или config (используя флаг include ).
- Мы принимаем файлы JavaScript в качестве входных данных (используя флаг allowJs ).
- Мы испускаем все выходные файлы в build (используя outDirflag ).
Заключение
Весь прошлый год я старался упростить свои инструменты JavaScript разработки и уйти от нарастающей сложности и избыточности, поражающей современную веб разработку. Использование аннотаций в комментариях неплохо позволяет придерживаться этой стратегии. Я получаю преимущества TypeScript не добавляя лишний шаг при сборке проекта во время разработки. Это похоже на использование TypeScript в качестве умного линтера, а не языка программирования. Мне даже не надо добавлять его в зависимости своего проекта. Я просто включаю проверку типов как простую функцию редактора и это позволяет мне лучше писать код.
Неточности в коде могут стоить сотен мегабайт оперативной памяти и многих часов, потраченных впустую, только из-за того, что информация о типе переменной приходит в редактор спустя полминуты после наведения курсора.
Если вы хотите перейти на TS, читайте эту статью, чтобы избежать ошибок Etsy и взять на вооружение лучшие решения компании. Подробности миграции рассказываем, пока у нас начинается курс по Fullstack-разработке на Python.
17000 файлов JS в Etsy охватывают множество итераций сайта. Разработчику бывает трудно понять, какие части кода считаются лучшей практикой, а какие устарели или считаются техническим долгом.
Полтора года назад мы модернизировали систему сборки JavaScript, чтобы включить стрелочные функции и классы. Эта модернизация означала защиту кодовой базы на будущее и более идиоматичный, масштабируемый JavaScript.
Несмотря на новые возможности, JS очень гибок и имеет мало ограничений. Писать на JavaScript без изучения деталей реализации зависимостей сложно. Облегчает труд документация, но она лишь предотвращает неправильное применение библиотеки. Итог — ненадёжный код.
Компилируем .ts файлы
Используя терминал, создайте новый каталог с названием ts-simple с помощью следующей команды:
Перейдите в этот каталог и создайте файл index.ts. Внутри этого файла мы создадим функцию с именем sayHello и принимаемым аргументом name с типом string.
Теперь используем tsc для компиляции нашего index.ts:
Эта команда создаст новый файл index.js, предварительно удалив типизацию из параметра, а также преобразовав файл в код ES5. Полученный файл можно запустить в браузере или использовать в Node. Ваш файл будет выглядеть следующим образом:
Чтобы проверить это, запустите созданный файл, используя следующую команду:
Подход open for business - добавление поддержки TS для существующих библиотек.
После того, как у вас появится некоторый практический опыт работы с TS и ваша команда разработчиков согласится, что стоит двигаться вперед, я предлагаю преобразовать ваши собственные библиотеки и модули для поддержки TS.
Это можно сделать двумя способами:
Первый способ предполагает использование файлов объявлений. Простое добавление файлов d.ts помогает компилятору TS проверять тип существующего кода JavaScript и обеспечивает поддержку автозаполнения в вашей среде IDE.
Это самый «дешевый» вариант, так как он вообще не требует изменения кода библиотеки. Это также дает вам максимальную мощность и поддержку типов в вашем будущем коде.
Второй способ - выполнить полную перезапись TypeScript, что может занять много времени и привести к ошибкам. Я бы не советовал это делать, если только это не докажет, что окупаемость инвестиций достойна вашей команды.
Рабочий пример
Для того чтоб включить анализ JavaScript кода с помощью TypeScript просто добавьте комментарий с текстом @ts-check в начало файла. Потом вы можете добавить аннотации с указанием типов в пределах этого файла. Следующий пример показывает описание сигнатуры функции с двумя параметрами и определённым типом возвращаемого значения.
Visual Studio Code, который поддерживает TypeScript из коробки, автоматически находит такие комментарии и включает режим проверки. Это не потребует абсолютно никакой настройки. Вам даже не надо создавать конфигурационный файл для TypeScript. Просто добавьте комментарии в любой JavaScript код. Если вы после этого попробуете вызвать функцию с неправильными аргументами, редактор покажет предупреждение.
Редактор так же будет использовать аннотации чтоб улучшить другие функции, такие как автодополнение. Кроме того, информация о типах успешно используется между файлами благодаря тому, что TypeScript понимает ES6 импорты и require в Node.js.
Вы так же можете использовать аннотации для указания структуры обычного объекта. Это может оказаться полезным когда вы хотите получить автодополнение свойств объекта и проверку их наличия для JSON данных полученных от какого-либо API. Следующий пример показывает как вы можете описать структуру объекта используя аннотации.
В этом примере используется специальная аннотация @typedef для определения типа объекта Issue . Далее в функции получения данных, мы указываем с помощью @type что полученный ответ представляет собой массив объектов Issue .
Вы можете найти больше примеров использования аннотаций в TypeScript wiki.
Добавить поддержку карты источника
Одна из больших проблем при добавлении TypeScript в ваш проект заключается в том, что вы добавляете слой косвенности между кодом, который вы пишете, и кодом, который фактически выполняется в рабочей среде (так как .ts транспилируется в .js во время выполнения).
Например, представьте следующую программу TypeScript:
Когда мы запустим его, он выдаст следующую трассировку стека:
Это проблематично, поскольку наша кодовая база содержит только файлы .ts . А поскольку большая часть производственного кода содержит сотни строк, правильный перевод этих чисел и файлов займет действительно много времени.
К счастью для нас, есть решение этой проблемы, называемое поддержкой исходной карты!
Это позволяет нам гарантировать, что трассировки стека будут иметь правильные имена файлов .ts и номера строк, как мы привыкли:)
Это можно сделать, запустив, npm install source-map-support а затем добавив следующую строку в первые строки вашего приложения:
Теперь код выглядит так:
И когда мы его компилируем, мы запускаем tsc --sourcemap hello.ts . Теперь мы получаем следующую трассировку стека, и это здорово:)
В последних версиях nodejs это поддерживается изначально с помощью флага --enable-source-maps .
Итоги
Прочтя этот материал, вы могли заметить то, как легко воспользоваться возможностями TypeScript в JavaScript-проекте. Для этого нужно лишь соответствующим образом настроить VS Code. Описанный здесь подход позволяет не вносить никаких изменений в процесс сборки проекта, не рисковать нарушением этого процесса, не принуждать команду разработчиков к срочному переходу на новый язык.
Если же JS-проект, в котором используются лишь некоторые возможности TypeScript, решено будет полностью перевести на TS, сделать это тоже несложно. К тому же, такой переход можно осуществлять поэтапно.
Вот GitHub-репозиторий, в котором можно найти примеры кода, использованные в этой статье.
Язык программирования TypeScript от Microsoft привносит многие преимущества статической типизации в JavaScript. Несмотря на то, что он не проверяет типы во время исполнения, он позволяет производить более точный статический анализ, повышает безопасность и открывает возможности для лучшей интеграции с IDE. Код на TypeScript обычно транспилируется в стандартный JavaScript, который выполняется в браузерах или Node.js. Учитывая привлекательность TypeScript, не удивительно, что его популярность быстро растёт.
Конечно, использование нестандартного диалекта языка не лишено объективных недостатков. Использование TypeScript в вашем проекте потребует дополнительного шага при сборке проекта, исключается возможность использования широкого набора инструментов, которые рассчитаны только на JavaScript. Так же, всем членам команды придется изучить нестандартные для JS функции. Так же, принимая во внимание скорость развития JavaScript, есть некоторый риск получить зависимость от нестандартного функционала. Разработчики TypeScript спроектировали язык с учётом некоторых потенциальных проблем, но, тем не менее, это не "ванильный" JavaScript.
К счастью, JavaScript разработчики могут получить некоторые из преимуществ используя привычный инструмент. В версии TypeScript 2.3, которая вышла в Апреле 2017 года, появилась поддержка анализа обычного JavaScript кода с указанием типов в комментариях. Вы можете использовать JSDoc подобный синтаксис для описания сигнатуры функций и добавления информации о типах. Инструменты TypeScript читают аннотации в комментариях и используют их практически так же как и в собственной системе типов.
JavaScript код с аннотациями в комментариях более многословен чем TypeScript, но он работает везде, не требует транспайлинга и позволяет избирательно использовать типизацию там, где это необходимо. Пока что он не покрывает все возможности TypeScript, но уже достаточно функционален, чтоб быть полезным.
Позаботьтесь о своем файле package.json
Вот как выглядит package.json до и после:
Как видите, большинство изменений касалось добавления префикса dist к большинству наших команд сборки. Мы также добавили скрипт build-dist , который компилирует нашу кодовую базу и перемещает все файлы в специальную папку с именем dist .
▍Типизация библиотек
В VS Code есть система автоматического получения типов для сторонних библиотек. Соответствующая процедура применяется ко всем пакетам, описанным в файле package.json . Но, если кто-то предпочитает задавать подобное в явном виде, он может внести соответствующие настройки в jsconfig.json :
После того, как система получения типов обработает библиотеку, типы можно будет использовать в JSDoc:
Поддержка команд после онбординга
Просмотр PR оказался хорошим способом раннего выявления проблем, и это послужило основой для многих последующих правил линтинга. Чтобы помочь с миграцией, мы решили явно просматривать каждый PR с TypeScript до тех пор, пока его внедрение не будет успешно.
Мы ограничили наши ревью синтаксисом и, по мере роста, обращались за помощью к инженерам, которые успешно перешли на TypeScript. Эту группу мы назвали TypeScript Advisors, и она стала бесценным источником поддержки новоиспечённых TypeScript-инженеров.
Одним из самых приятных моментов внедрения оказалась органичность обучения. Команды незаметно проводили большие парные сессии, на которых решали проблемы или пытались вместе мигрировать файл. Некоторые даже создали книжные клубы, чтобы читать книги по TypeScript. Подобные миграции — большой труд, но легко забыть о том, как много этой работы делают увлечённые коллеги и члены команды.
Самые интересные детали и проблемы
Самым простым в миграции оказалось добавление поддержки TS в сборку. Вот интересные моменты:
Для сборки JS мы используем Webpack, последний с помощью Babel транспилирует современный JavaScript в старый, более совместимый.
Замечательный плагин babel-preset-typescript быстро превращает TypeScript в JavaScript, но проверку типов нужно делать самостоятельно.
Для проверки типов как часть набора тестов запускался компилятор TypeScript. Опция noEmit сообщала компилятору не транспилировать файлы.
Всё это заняло менее двух недель. Большая часть времени ушла на проверку того, что TypeScript в производственной среде не ведёт себя странно. Другие инструменты заняли больше времени и оказались интереснее.
▍Вариант №3. Включение проверки для отдельных файлов
Третий способ использования TypeScript для контроля JS-кода предназначен для включения проверки на уровне отдельных файлов. Он заключается в добавлении в начало файла соответствующего комментария:
Используя ту же идею, можно выключить TS-проверку для отдельного JS-файла. Делается это в том случае, если TS-проверка включена глобально с использованием вышеописанных способов. Тут тоже используется специальный комментарий:
А если надо, чтобы TypeScript игнорировал бы лишь часть файла, можно поступить так:
Вывод
Typescript супер! Если вы пишете программное обеспечение производственного уровня, а бизнес-требования и доступность высоки, я настоятельно рекомендую вам попробовать Typescript.
Просто не забывайте делать это шаг за шагом. Новые языки и фреймворки сложны, поэтому найдите время, чтобы изучить и обучить себя и свою команду, прежде чем продвигать этот процесс.
Создайте короткий цикл обратной связи и ценностное предложение. Трудно «продать» новый язык вашей команде и руководству, поскольку это требует времени и ресурсов.
Поэтому разработайте процесс миграции с короткими циклами обратной связи и попытайтесь определить четкие KPI (меньше ошибок в производстве, более легкое время рефакторинга и т. д.) И убедитесь, что ценностное предложение для вашего варианта использования постоянно оправдывается, пока оно не станет де- факто стандарт.
Обучение и онбординг
Мы потратили на обучение TypeScript много времени, и это решение оказалось лучшим за всю миграцию. Немногие из сотен инженеров Etsy, включая меня, имели опыт работы с TypeScript. И, если включить рубильник и сказать: "Всё готово”, это вызовет у людей замешательство, команду завалят вопросами, а скорость инженеров упадёт.
Подключая команды постепенно, мы работали над инструментами и учебными материалами. Ни один инженер не писал на TypeScript без ревью со стороны, а постепенное внедрение давало время на изучение и включение языка в планы разработки.
Создайте свой первый файл .TS в своем проекте
Я рекомендую начать с добавления простого файла TypeScript (или изменения действительно простого файла JS на файл TS) и развертывания. Выполняйте эту миграцию поэтапно.
Читайте также: