Можно ли использовать typescript в js файлах

Обновлено: 04.07.2024

Язык программирования TypeScript на самом деле является надмножеством JavaScript. Если вы используете JavaScript, то уже пишете на TypeScript. Это не значит, что вы пишете хороший код на TypeScript и задействуете все его средства. Но это значит, что вы сможете плавно перевести существующую кодовую базу JavaScript в TypeScript и быстрее начать использовать преимущества новых средств TypeScript.

В этой статье я дам рекомендации по переводу приложения с JavaScript на TypeScript. Вы узнаете, как перейти с JavaScript на TypeScript, чтобы использовать систему типов TypeScript, помогающую писать более качественный код. Благодаря средствам статического анализа TypeScript вы сведете к минимуму количество ошибок и повысите производительность своего труда. Следуя этим рекомендациям, вы также минимизируете количество ошибок и предупреждений от системы типов TypeScript в ходе миграции.

В качестве примера я начну с приложения, которое управляет адресной книгой. Это одностраничное приложение (Single-Page Application, SPA), использующее JavaScript на клиенте. Для целей этой статьи я не стану его усложнять и включу лишь ту порцию, которая отображает список контактов. Оно использует инфраструктуру Angular для связывания с данными и поддержки другой функциональности. Эта инфраструктура обрабатывает связывание с данными и создание шаблонов для отображения информации о контактах.

Приложение образуют три JavaScript-файла: app.js (содержит код, запускающий приложение), contactsController.js (контроллер страницы со списком) и contactsData.js (хранит список контактов, которые будут отображаться). Контроллер наряду с инфраструктурой Angular обрабатывает поведение страницы со списком. Вы можете сортировать контакты и показывать или скрывать более подробную информацию о любом из контактов. Файл contactsData.js содержит набор контактов, «зашитых» в код. В производственном приложении этот файл должен содержать код для вызова сервера и получения данных от него. Но «зашитый» в код список контактов лучше подходит для целей демонстрации.

Не волнуйтесь, если у вас нет особого опыта в работе с Angular. Вы сами убедитесь, насколько легко с ней работать, когда я начну перевод приложения на TypeScript. Приложение следует соглашениям Angular, которые легко сохранить при миграции на TypeScript.

Перевод приложения на TypeScript лучше всего начинать с файла контроллера. Поскольку любой допустимый код на JavaScript также является допустимым кодом на TypeScript, просто смените расширение файла контроллера contactsController с .js на .ts. TypeScript — полноправный язык в Visual Studio 2013 Update 2. Если у вас установлено расширение Web Essentials, вы увидите в одном окне как исходный код на TypeScript, так и генерируемый вывод JavaScript (рис. 1).

Редактирование TypeScript в Visual Studio 2013 Update 2

Рис. 1. Редактирование TypeScript в Visual Studio 2013 Update 2

Поскольку специфичные для TypeScript языковые средства пока не используются, эти два представления практически одинаковы. Дополнительная строка комментария в конце предоставляет информацию для Visual Studio при отладке TypeScript-приложений. Используя Visual Studio, приложение можно отлаживать на уровне TypeScript, а не на уровне сгенерированного исходного JavaScript-кода.

Как видите, компилятор TypeScript сообщает об ошибке для этого приложения, хотя компилятор генерирует допустимый JavaScript-вывод. Это одна из сильных сторон языка TypeScript. Это естественное следствие того правила, что TypeScript является надмножеством JavaScript. Я еще не объявил символ contactsApp ни в одном из TypeScript-файлов. Поэтому компилятор TypeScript предполагает тип any и считает, что данный символ будет ссылаться на объект в период выполнения. Несмотря на эти ошибки, я могу запустить приложение и оно по-прежнему будет корректно работать.

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

Для contactsApp легко объявить внешнюю переменную. По умолчанию она имеет тип any:

Хотя это устраняет ошибку при компиляции, это не помогает избежать ошибок при вызове методов в библиотеке Angular. Тип any — именно то, что подразумевает его название: это может быть что угодно. TypeScript не будет выполнять проверку типа any при доступе к переменной contactsApp. Чтобы активизировать проверку типов, нужно сообщить TypeScript о типе contactsApp и о типах, определенных в инфраструктуре Angular.

TypeScript включает информацию о типах для существующих JavaScript-библиотек с помощью такого средства, как Type Definitions. Type Definitions — это набор объявлений без реализаций. Они описывают типы и их API компилятору TypeScript. Проект DefinitelyTyped на GitHub имеет определения типов для многих популярных JavaScript-библиотек, включая Angular.js. Я включил эти определения в свой проект, используя диспетчер NuGet-пакетов.

После включения Type Definitions для библиотеки Angular я могу использовать их для устранения ошибок компиляции, которые мы уже видели. Мне нужно ссылаться на информацию о типах, только что добавленную в проект. Для этого есть специальный комментарий, который сообщает компилятору TypeScript ссылаться на информацию о типах:

Теперь компилятор TypeScript может интерпретировать любые типы, определенные в файле Type Definition — angular.d.ts. Давайте исправим тип переменной contactsApp. Ожидаемый тип переменной contactsApp, объявленный в пространстве имен ng в app.js, — IModule:

Благодаря этому объявлению я получу поддержку IntelliSense при вводе точки после contactsApp. Кроме того, я буду получать отчеты об ошибках от компилятора TypeScript всякий раз, когда буду неправильно набирать или использовать API, объявленные в объекте contactsApp. Теперь ошибки компиляции исчезают, и я включил информацию о статических типах для объекта app.

Но остальному коду в объекте contactsController по-прежнему недостает информации о типах. Пока вы не добавите аннотации типов, компилятор TypeScript будет предполагать, что тип любой переменной — any. Второй параметр в методе contactsApp.controller — это функция, и первый параметр этой функции, $scope, имеет тип ng.IScope. Поэтому я включу этот тип в объявление функции (contactData все равно будет интерпретироваться как тип any):

Это вызывает появление нового набора ошибок компиляции. Новые ошибки возникают из-за того, что код внутри функции contactsController манипулирует свойствами, которые не являются частью типа ng.IScope. Ng.IScope — это интерфейс, и реальный объект $scope — специфичный для конкретного приложения тип, который реализует IScope. Проблемные свойства являются членами этого типа. Чтобы задействовать статическую типизацию TypeScript, я должен определить специфичный для приложения тип. Я назову его IContactsScope:

Как только этот интерфейс определен, я просто изменяю тип переменной $scope в объявлении функции:

После внесения этих изменений можно скомпилировать приложение без ошибок, и оно будет корректно работать. При добавлении этого интерфейса обратите внимание на несколько важных концепций. Мне не пришлось искать любой другой код и объявлять, что какой-либо конкретный тип реализует тип IContactsScope. TypeScript поддерживает структурную типизацию, собирательно называемую «утиной типизацией» (duck typing), или неявной типизацией. Это означает, что любой объект, который объявляет свойства и методы, объявленные в IContactsScope, реализует интерфейс IContactsScope независимо от того, объявлено ли в этом типе, что он реализует IContactsScope.

Заметьте, что я использую TypeScript-тип any как подстановку в определении IContactsScope. Свойство contacts представляет список контактов, а я пока не перенес тип Contact. В таком случае any можно использовать как подстановку, и компилятор TypeScript не станет выполнять проверку типа any при обращении к этим значениям. Это удобный метод при миграции приложения.

Тип any представляет любые типы, которые я пока не перенес из JavaScript в TypeScript. Это обеспечивает более плавную миграцию и уменьшает количество ошибок от компилятора TypeScript, которые приходится исправлять на каждой итерации. Я также могу искать переменные, объявленные как тип any, и тем самым узнавать, какую работу мне еще предстоит проделать. Any сообщает компилятору TypeScript не выполнять проверку типа данной переменной. Он может быть любым. Компилятор будет предполагать, что вам известны API, доступные в этой переменной. Это не значит, что каждый случай использования any плох. Существуют допустимые случаи применения типа any, например когда какой-то JavaScript API рассчитан на работу с разными типами объектов. Использование any как подстановки при миграции — один из таких полезных случаев.

Наконец, объявление toggleShowDetails показывает, как объявления функций представляются в TypeScript:

Имя функции — toggleShowDetails. После двоеточия вы видите список параметров. Эта функция принимает единственный параметр, в настоящее время имеющий тип any. Имя contact не обязательно. Вы можете использовать его, чтобы предоставить больше информации другим программистам. Стрелка указывает возвращаемый тип — в данном примере это boolean.

Наличие типа any в определении IContactScope подсказывает вам, где надо приложить очередные усилия. TypeScript помогает избегать ошибок, когда вы даете ему больше информации о типах, с которыми вы работаете. Я заменю этот any определением того, что содержится в contact, определив тип IContact, который включает свойства, доступные в объекте contact (рис. 2).

Рис. 2. Включение свойств в объект contact

Определив интерфейс IContact, я буду использовать его в интерфейсе IContactScope:

Мне не нужно добавлять информацию о типах в определение функции toggleShowDetails, определенной в функции contactsController. Поскольку переменная $scope имеет тип IContactsScope, компилятор TypeScript знает, что функция, назначенная toggleShowDetails, должна соответствовать прототипу функции, определенному в IContactScope, а у параметра должен быть тип IContact.

Посмотрите на сгенерированный JavaScript для этой версии contactsController на рис. 3. Заметьте, что все определенные мной типы интерфейсов удалены из сгенерированного JavaScript. Аннотации типов существуют только для вас и для средств статического анализа. Эти аннотации не переносятся в сгенерированный JavaScript, поскольку они там не нужны.

Рис. 3. TypeScript-версия контроллера и сгенерированный JavaScript

Добавление определений модуля и класса

Включение аннотаций типов в ваш код позволяет средствам статического анализа находить и сообщать о возможных ошибках, которые вы допустили в своем коде. Это охватывает все — от IntelliSense и анализа сомнительных синтаксических конструкций (lint-like analysis) до ошибок и предупреждений на этапе компиляции.

Еще одно важное преимущество TypeScript над JavaScript — более качественный синтаксис для определения области видимости типов. Ключевое слово module в TypeScript позволяет помещать определения типов в эту область видимости и избегать конфликтов с типами из других модулей, у которых могут быть те же имена.

Включение аннотаций типов в ваш код позволяет средствам статического анализа находить и сообщать о возможных ошибках, которые вы допустили в своем коде.

Мое приложение-пример не настолько велико, но размещение определений типов в модулях все равно хороший стиль, помогающий избегать конфликтов. Здесь я помещу contactsController и другие определенные мной типы в модуль Rolodex:

Я не добавил ключевое слово export ни в одно из определений в этом модуле. Это означает, что на типы, определенные в модуле Rolodex, можно ссылаться только в пределах этого модуля. Я введу ключевое слово export в интерфейсы, определенные в этом модуле, и задействую эти типы позднее, когда буду переносить код contactsData. Я также изменю код для ContactsController и превращу функцию в класс. Этому классу нужен конструктор для инициализации, но другие открытые методы не требуются (рис. 4).

Рис. 4. Преобразование ContactsController из функции в класс

Создание этого типа меняет вызов contactsApp.controller. Вторым параметром теперь является тип класса (class type), а не функция, определенная ранее. Первый параметр функции контроллера — это имя контроллера. Angular сопоставляет имена контроллеров с функциями-конструкторами. Везде, где в HTML-странице есть ссылки на тип ContactsController, Angular будет вызывать конструктор класса ContactsController:

Тип контроллера полностью перенесен из JavaScript в TypeScript. Новая версия содержит аннотации для всех типов, определенных или используемых в контроллере. В TypeScript Я мог бы сделать это без изменений в других частях приложения. Никакие иные файлы не были затронуты. Смешивание TypeScript с JavaScript проходит плавно, упрощая добавление TypeScript в существующее JavaScript-приложение. Система типов TypeScript опирается на логическое распознавание типов (type inference) и структурную типизацию, что облегчает взаимодействие между TypeScript и JavaScript.

Теперь перейдем к файлу contactData.js (рис. 5). Эта функция использует метод фабрики Angular и возвращает объект, который содержит список контактов. Как и контроллер, метод фабрики сопоставляет имена (contactData) с функцией, возвращающей сервис. Это соглашение применяется в конструкторе контроллера. Второй параметр конструктора называется contactData. Angular использует имя этого параметра для сопоставления с нужной фабрикой. Как видите, инфраструктура Angular основана на соглашениях.

Рис. 5. JavaScript-версия сервиса contactData

И вновь первый шаг — простая смена расширения с .js на .ts. Файл нормально компилируется, и сгенерированный JavaScript практически совпадает с исходным TypeScript. Далее я помещу код из файла contactData.ts в тот же модуль Rolodex. Это ограничит область видимости всего кода для приложения одним и тем же логическим разделом.

Затем я перенесу фабрику contactData в класс. Объявим класс как тип ContactDataServer. Вместо функции, которая возвращает объект с двумя свойствами, являющимися методами, я могу просто определить эти методы как члены объекта ContactDataServer. Начальными данным теперь является элемент данных объекта типа ContactDataServer. Мне также понадобится использовать этот тип в вызове contactsApp.factory:

Окончательная версия показана на рис. 6. Заметьте, что я добавил информацию о типах для массива контактов и входного параметра в методе addContact. Аннотации типов не обязательны — код на TypeScript допустим и без них. Но я все же советую добавлять всю необходимую информацию о типах в ваш код на TypeScript, потому что это помогает избегать ошибок в системе типов TypeScript.

Рис. 6. TypeScript-версия ContactDataServer

Теперь, когда я создал новый класс ContactDataServer, я могу внести последнее изменение в контроллер. Вспомните: второй параметр конструктора contactsController был сервером данных. Сейчас это можно сделать более безопасным способом, объявив, что следующий параметр должен быть типа ContactDataServer:

Плавный переход с JavaScript на TypeScript

В TypeScript гораздо больше средств, чем было продемонстрировано здесь. По мере работы с TypeScript вы изучите эти средства. Чем чаще вы будете пользоваться TypeScript-расширениями JavaScript, тем больше повысится производительность вашего труда. Помните, что аннотации типов TypeScript предназначены для плавного перехода с JavaScript на TypeScript. И самое важное: учитывайте, что TypeScript — это надмножество JavaScript. То есть любой допустимый JavaScript-код является допустимым TypeScript-кодом.

Кроме того, аннотации типов TypeScript проверяются только там, где вы их предоставляете, и вы не обязаны добавлять их повсюду. Еще раз повторюсь, что они очень полезны при переходе с JavaScript на TypeScript.

Наконец, система типов TypeScript поддерживает структурную типизацию. Когда вы определяете интерфейсы для важных типов, система типов TypeScript будет предполагать, что любой объект с этими методами и свойствами поддерживает данный интерфейс. От вас не требуется объявлять поддержку интерфейса в определении каждого класса. Анонимные объекты тоже могут поддерживать интерфейсы, используя структурную типизацию.

Сочетание всех этих средств обеспечивает плавный перевод вашей кодовой базы с JavaScript под TypeScript. Чем дальше вы продвигаетесь по пути миграции, тем больше преимуществ вы получаете от статического анализа кода в TypeScript. Вашей конечной целью должно стать использование как можно большей надежности TypeScript. Попутно существующий у вас JavaScript-код будет функционировать как допустимый TypeScript-код, не использующий аннотации типов TypeScript. Этот процесс проходит почти без трения. У вас нет никаких причин на то, чтобы не использовать TypeScript в своих текущих JavaScript-приложениях.

Выражаю благодарность за рецензирование статьи эксперту Microsoft Джонатану Тернеру (Jonathan Turner).

Я — большой любитель TypeScript. По возможности я стараюсь использовать этот язык в своих проектах. TypeScript даёт разработчику отчёты об ошибках и проверку типов в JavaScript и TypeScript-коде. Кроме того, тот, кто пишет на TypeScript, может пользоваться удобными возможностями по автозавершению кода, может, быстро и надёжно, выполнять рефакторинг. TypeScript — это первая линия обороны от ошибок в коде. Ещё одна сильная сторона этого языка заключается в том, что он позволяет, при написании программ, пользоваться самыми свежими возможностями JavaScript. При этом то, что получается при преобразовании TypeScript-кода в JavaScript, будет поддерживаться всеми браузерами. Это очень приятно.


Правда, не все фронтенд-проекты предусматривают применение TypeScript. Что если можно было бы пользоваться возможностями TypeScript, но при этом не переводить на него весь проект (и всю команду), и не добавлять в конвейер сборки проекта новый инструмент? Это возможно благодаря VS Code и JSDoc.

Настройка рабочей среды

▍Вариант №1. Настройки VS Code (глобальная проверка)

Первый способ использования TypeScript (TS) в проектах, написанных на обычном JavaScript (JS), заключается в том, чтобы применять TS для проверки всех JS-файлов. Делается это посредством включения одного глобального параметра VS Code. Этот параметр можно включить в настройках пользователя или рабочего пространства:


Если вы из тех, кто предпочитает пользоваться графическим интерфейсом, то включить это можно так, как показано ниже.


Включение проверки JS-кода средствами TypeScript

▍Вариант №2. Использование файла jsconfig.json (глобальная проверка)

Ещё один вариант включения глобальной проверки JS-кода средствами TS заключается в использовании файла jsconfig.json . Если такой файл имеется, настройки, заданные в нём, переопределят настройки, заданные в VS Code.

▍Вариант №3. Включение проверки для отдельных файлов

Третий способ использования TypeScript для контроля JS-кода предназначен для включения проверки на уровне отдельных файлов. Он заключается в добавлении в начало файла соответствующего комментария:


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


А если надо, чтобы TypeScript игнорировал бы лишь часть файла, можно поступить так:

Типизация кода с использованием JSDoc

Только что мы поговорили о том, как включать TS-проверку на уровне файлов. Это даёт базовые возможности по проверке типов. Их можно расширить, описывая типы с помощью комментариев формата JSDoc.

▍Типизация функций

Начать типизацию кода средствами JSDoc можно с описания того, что функции принимают на вход:


После этого редактор сможет выдавать подсказки по типам.


Подсказка по типу значения, принимаемого функцией

Этот метод хорошо подходит для простых типов, но что если разработчику нужно описывать собственные типы? Сделать это можно с помощью тега @typedef . Рекомендую помещать описания типов в начале файла. Это облегчит обнаружение таких описаний в ходе работы:


Такие описания можно использовать там, где это нужно:


Ещё один вариант применения этой методики заключается в перемещении объявлений типов в особые файлы. Скажем, такой файл может называться main.d.ts .


Эти типы потом можно использовать в JavaScript:

▍Типизация обычного кода

Вышеприведённые примеры решают задачу типизацию входных и выходных значений функций. Нечто подобное можно делать и с помощью встроенных в код JSDoc-комментариев.


Типизация обычной переменной

▍Типизация библиотек

В VS Code есть система автоматического получения типов для сторонних библиотек. Соответствующая процедура применяется ко всем пакетам, описанным в файле package.json . Но, если кто-то предпочитает задавать подобное в явном виде, он может внести соответствующие настройки в jsconfig.json :


После того, как система получения типов обработает библиотеку, типы можно будет использовать в JSDoc:

Переход на TypeScript

Если вы решили перевести на TypeScript JavaScript-проект, в некоторых частях которого используется TypeScript, можно просто переименовать jsconfig.json в tsconfig.json и включить в нём параметр allowJs :


После этого можно приступать к переименованию *.js -файлов в *.ts -файлы и к типизации кода этих файлов. Процесс перевода проекта на TypeScript может происходить постепенно.

Итоги

Прочтя этот материал, вы могли заметить то, как легко воспользоваться возможностями TypeScript в JavaScript-проекте. Для этого нужно лишь соответствующим образом настроить VS Code. Описанный здесь подход позволяет не вносить никаких изменений в процесс сборки проекта, не рисковать нарушением этого процесса, не принуждать команду разработчиков к срочному переходу на новый язык.

Если же JS-проект, в котором используются лишь некоторые возможности TypeScript, решено будет полностью перевести на TS, сделать это тоже несложно. К тому же, такой переход можно осуществлять поэтапно.

Вот GitHub-репозиторий, в котором можно найти примеры кода, использованные в этой статье.


Я люблю писать код. И я хочу быть в этом действительно хорош. Но почему-то написание JavaScript никогда не было моей сильной стороной.

Сколько бы я ни практиковался, в продакшене продолжали появляться одни и те же ошибки: исключения cannot read property <> of undefined , знаменитая строка [Object object] и даже вызовы функций с недопустимым количеством параметров.

Более того, большинство кодовых баз, над которыми я работал, были действительно большими JavaScript-базами. Вот хорошая диаграмма того, как я себя чувствовал:


Мы можем сделать намного лучше!

В этом посте я не буду объяснять, почему TypeScript великолепен (и это так), и сосредоточусь на задачах, которые вам нужно выполнить, если вы хотите перенести свой обычный проект JavaScript в смешанный проект TypeScript.

К концу поста вы станете более счастливым человеком и сможете ответить на следующие вопросы:

  1. Как я могу добавить типы в свой проект JavaScript?
  2. Что такое TypeScript?
  3. Как я могу использовать TypeScript в проекте JavaScript?
  4. Что нужно сделать, чтобы преобразовать приложение JavaScript для поддержки TypeScript?
  5. Как я могу позаботиться о сборке и упаковке?
  6. Как мне позаботиться о линтинге?
  7. Как я могу «продать» TypeScript моей организации и разработчикам?

Как я могу добавить типы в свой проект JavaScript?

Vanilla JavaScript в настоящее время не поддерживает типы, поэтому для этого нам нужна какая-то абстракция поверх JavaScript.

Некоторые распространенные абстракции используют статическую проверку типов Facebook под названием flow и язык Microsoft под названием typescript .

Что такое машинописный текст?

TypeScript - это типизированное надмножество JavaScript, которое компилируется в обычный JavaScript.

Если вы знаете javascript, вы уже на полпути.

TypeScript состоит из нескольких частей. Первый - это язык TypeScript - это новый язык, содержащий все функции JavaScript. Ознакомьтесь со спецификациями для получения дополнительной информации.

Второй - компилятор TypeScript tsc (механизм системы типов), это механизм компиляции, который создает ts-файлы и выдает js-файлы.

Hello world в TypeScript

В качестве примера, вот шаги, которые вам нужно предпринять, чтобы написать свое первое приложение TypeScript:

  1. установить TypeScript с помощью npm i typescript
  2. создайте папку с именем example и cd (в вашем терминале)
  3. создать файл с именем hello.world.ts
  4. напишите в нем следующий код:
Hello world в TypeScript - моя первая программа на TypeScript!

а затем сохраните его.

5. запустите команду tsc для запуска компилятора TypeScript в текущей папке.

6. обратите внимание, что у вас есть файл hello.js , который теперь можно запустить:)

7. запустить node ./hello.js

Как я могу использовать TypeScript в проекте JavaScript?

Есть несколько стратегий для выполнения этой «миграции» (с точки зрения компании и кода). Я перечислил их ниже по их «стоимости» и по степени ценности.

Я бы посоветовал начать с «поддержки приложений TS» и двигаться дальше после того, как вы доказали ценность для своей команды разработчиков.

Процесс миграции TypeScript выполняется итеративно, только если вы подтверждаете ценность.

Процесс миграции TypeScript выполняется итеративно, только если вы подтверждаете ценность.

Подход «маленький шаг для человека» - добавление поддержки TS для существующих приложений

Один маленький шаг для разработчика.

Мое первое предложение - создать смесь двух языков в одном проекте, а затем написать весь «будущий» код на TypeScript.

Комбинация двух языков в одном проекте сначала звучит ужасно, но работает достаточно хорошо, поскольку TS был построен для постепенного использования. Сначала его можно использовать как JS с файлами .ts и странными строками импорта.

В этой стратегии мы будем компилировать перенесенные файлы TypeScript и просто копировать файлы JavaScript в папку вывода.

Огромное преимущество этого подхода заключается в том, что он позволяет команде разработчиков (и вам) постепенно обучаться языку и его функциям. Это также дает вам практический опыт и понимание его плюсов и минусов.

Я настоятельно рекомендую начать с этого шага, а затем повторить его вместе со своей командой, прежде чем двигаться дальше. Чтобы быстро узнать, как это сделать, прокрутите вниз до раздела The steps to convert a javascript application to support typescript .

Подход open for business - добавление поддержки TS для существующих библиотек.

После того, как у вас появится некоторый практический опыт работы с TS и ваша команда разработчиков согласится, что стоит двигаться вперед, я предлагаю преобразовать ваши собственные библиотеки и модули для поддержки TS.

Это можно сделать двумя способами:

Первый способ предполагает использование файлов объявлений. Простое добавление файлов d.ts помогает компилятору TS проверять тип существующего кода JavaScript и обеспечивает поддержку автозаполнения в вашей среде IDE.

Это самый «дешевый» вариант, так как он вообще не требует изменения кода библиотеки. Это также дает вам максимальную мощность и поддержку типов в вашем будущем коде.

Второй способ - выполнить полную перезапись TypeScript, что может занять много времени и привести к ошибкам. Я бы не советовал это делать, если только это не докажет, что окупаемость инвестиций достойна вашей команды.

Скелет - шаг в будущее

Каркас Typescript - залог светлого будущего!

Я предполагаю, что большинство разработчиков «ленивы» и обычно запускают свое приложение с копирования из каркаса (который обычно содержит журналы, показатели, конфигурацию и так далее).

Этот шаг поможет вам проложить свой путь в светлое будущее, создав «официальный» каркас вашей компании. Это будет 100% TS, и устаревший каркас JS, если он существует.

Этот стартовый узел typescript - действительно хороший первый проект для начала.

Комплексный подход - преобразование полной кодовой базы из JS в TS

Этот вариант требует полной перезаписи кода JavaScript на TypeScript.

Я бы порекомендовал сделать это в качестве последнего шага в процессе миграции TS, поскольку он требует полной переписывания приложения и глубоких знаний TypeScript и его функций.

Вы можете выполнить такую ​​перезапись (это долгий процесс) следующим образом:

Имейте в виду, что есть автоматизированные инструменты, призванные облегчить этот процесс, например ts-migrate от команды Airbnb.

Он решает эту проблему с другой точки зрения и конвертирует все файлы в TypeScript. Это также позволяет постепенно улучшать (как указано в шагах выше), в то время как вся кодовая база является TypeScript с первого дня.

Как преобразовать приложение JavaScript для поддержки TypeScript.

Установить машинописный текст

запустить: npm install typescript .

Конфигурационный файл Typescript

Добавьте файл конфигурации TypeScript, который можно создать с помощью команды tsc --init в вашем интерфейсе командной строки.

Вот пример того, как выглядела наша первоначальная конфигурация:

Несколько замечаний выше:

  1. Мы читаем все файлы в каталоге src или test или config (используя флаг include ).
  2. Мы принимаем файлы JavaScript в качестве входных данных (используя флаг allowJs ).
  3. Мы испускаем все выходные файлы в build (используя outDirflag ).

Создайте свой первый файл .TS в своем проекте

Я рекомендую начать с добавления простого файла TypeScript (или изменения действительно простого файла JS на файл TS) и развертывания. Выполняйте эту миграцию поэтапно.

Позаботьтесь о своем файле package.json

Вот как выглядит package.json до и после:

Как видите, большинство изменений касалось добавления префикса dist к большинству наших команд сборки. Мы также добавили скрипт build-dist , который компилирует нашу кодовую базу и перемещает все файлы в специальную папку с именем dist .

Добавить поддержку карты источника

Одна из больших проблем при добавлении TypeScript в ваш проект заключается в том, что вы добавляете слой косвенности между кодом, который вы пишете, и кодом, который фактически выполняется в рабочей среде (так как .ts транспилируется в .js во время выполнения).

Например, представьте следующую программу TypeScript:

Когда мы запустим его, он выдаст следующую трассировку стека:

Подождите! но в нашем машинописном коде всего 2 строки!

Это проблематично, поскольку наша кодовая база содержит только файлы .ts . А поскольку большая часть производственного кода содержит сотни строк, правильный перевод этих чисел и файлов займет действительно много времени.

К счастью для нас, есть решение этой проблемы, называемое поддержкой исходной карты!

Это позволяет нам гарантировать, что трассировки стека будут иметь правильные имена файлов .ts и номера строк, как мы привыкли:)

Это можно сделать, запустив, npm install source-map-support а затем добавив следующую строку в первые строки вашего приложения:

Теперь код выглядит так:

И когда мы его компилируем, мы запускаем tsc --sourcemap hello.ts . Теперь мы получаем следующую трассировку стека, и это здорово:)

В последних версиях nodejs это поддерживается изначально с помощью флага --enable-source-maps .

Как заботиться о сборке и упаковке

Давайте просто рассмотрим изменения до и после в нашем файле конфигурации сборки.

Вот так наш файл .travis выглядел раньше (упрощенная версия):

И вот как он выглядел после этого:

Обратите внимание, что большинство изменений касается «упаковки» файла tar.xz и выполнения команды build-dist перед доступом к папке dist .

Как мне позаботиться о линтинге?

Доступно несколько вариантов линтинга.

Первым решением, которое мы использовали, было tsfmt, но позже мы отказались от него, потому что оно требует от вас поддержки двух отдельных конфигураций для вашего проекта (для TypeScript через sfmt и отдельный для JavaScript, с помощью eslint ). Проект также выглядит устаревшим.

Затем мы нашли TSLint, который перенаправил нас на плагин eslint для TypeScript. Затем мы настроили его следующим образом:

Это был наш eslintrc.js :

Который мы настроили для запуска с помощью команды lint-fix в нашем package.json который выглядит следующим образом:

Как «продать» машинописный текст вашей команде разработчиков

Я считаю, что одним из наиболее важных аспектов внедрения TypeScript в вашу организацию является «pitch» и то, как вы представляете его своей команде разработчиков.

Вот презентация, которую мы представили внутри компании, которая вращалась вокруг следующих тем:

  1. Объясните, почему мы считаем TypeScript крутым
  2. Что такое TypeScript
  3. Некоторые базовые примеры кода. Главное в этой части - не «обучать» 100% TypeScript, поскольку люди будут делать это сами. Вместо этого дайте людям почувствовать, что они могут читать и писать TypeScript и что кривая обучения не так уж и сложна.
  4. Расширенные примеры кода, такие как типы Union и алгебраические типы данных, которые предоставляют огромные возможности JS-разработчику. Это настоящие удовольствия, помимо типизированного языка и компилятора, который привлечет к нему ваших разработчиков.
  5. Как начать пользоваться. Поощряйте людей загрузить IDE vs-code и добавить аннотацию ( // @ ts-check), чтобы они могли начать видеть волшебство! В нашей компании мы заранее подготовили некоторые действительно крутые ошибки, которые выявляют ts-check , и мы провели живую демонстрацию (2-3 минуты), чтобы показать, насколько быстро компилятор TypeScript может помочь им с помощью документов JS с аннотациями типов или ts-check ).
  6. Погрузитесь в некоторые особенности. Объясните файлы ts.d и @types packages которые являются одними из вещей, которые вы действительно встретите в самом начале TypeScript программы.
  7. Живой пиар от вашей работы. Мы показали PR, который мы создали на раннем этапе, и призвали людей просмотреть его и попробовать на себе.
  8. Поделитесь классными ресурсами. В сети много контента, и сложно отличить хорошее от плохого. Копайте глубже и постарайтесь найти качественный контент об инструментах, которые вы используете и которые вам нужны.
  9. Создайте публичный пул-реквест. Я рекомендую попытаться получить как можно больше поддержки для его утверждения.

Добавление typescript в проект!Ура!&nbsp;

10. Создайте в своей организации положительный отзыв об изменениях!

Я настоятельно рекомендую настроить этот список в соответствии с вашей командой, стандартами и ограничениями по времени.

Я настоятельно рекомендую настроить этот список в соответствии с вашей командой, стандартами и ограничениями по времени.

Вывод

Typescript супер! Если вы пишете программное обеспечение производственного уровня, а бизнес-требования и доступность высоки, я настоятельно рекомендую вам попробовать Typescript.

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

Создайте короткий цикл обратной связи и ценностное предложение. Трудно «продать» новый язык вашей команде и руководству, поскольку это требует времени и ресурсов.

Поэтому разработайте процесс миграции с короткими циклами обратной связи и попытайтесь определить четкие KPI (меньше ошибок в производстве, более легкое время рефакторинга и т. д.) И убедитесь, что ценностное предложение для вашего варианта использования постоянно оправдывается, пока оно не станет де- факто стандарт.

Как использовать аннотации типов в файлах JavaScript главное изображение

TypeScript (TS) позволяет использовать аннотации типов в коде JavaScript. TS даже может проверять код при сборке, благодаря чему вы увидите ошибки до того, как они попадут в продакшен. Вы избавитесь от undefined is not a function навсегда.

TypeScript по умолчанию требует некоторых изменений при настройке окружения. Вам придётся переименовать файлы JavaScript в .ts, .tsx, а также использовать компиляторы tsc или Babel.

Синтаксис TypeScript

Часто людям не нравится работать с TypeScript из-за необходимости использовать новый для них синтаксис. Если вам знакома эта ситуация, статья как раз для вас.

Синтаксис TypeScript позволяет использовать аннотации типов инлайн. Но сначала поговорим об альтернативах.

Документируем JavaScript

Синтаксис JSDoc

TypeScript можно документировать с помощью JSDoc. Это стандартный синтаксис для документирования JavaScript. JSDoc используется для создания документации, но TypeScript понимает аннотации типов, созданные с помощью этого инструмента.

Это значит, что у вас есть возможности использовать преимущество TypeScript, в частности, проверку типов, без необходимости конвертировать весь код.

Почему JSDoc

Применение JSDoc — полезная практика, даже если вы не используете TypeScript. Фактически это стандарт документирования JavaScript, и его поддерживают разные инструменты и редакторы.

Если вы уже применяете JSDoc, вам будет удобно использовать проверку типов в коде, аналогичную той, которая применяется в TypeScript. Для этого нужно уделить время настройке TypeScript.

Установка TypeScript

Как установить TypeScript

Чтобы установить в проект TypeScript, используйте такую команду:

Как включить проверку типов JSDoc

Теперь нужно настроить TypeScript, чтобы он проверял код в файлах JavaScript. По умолчанию он проверяет только файлы с расширением .ts . Настройки TypeScript надо указывать в файле tsconfig.json . Обратите внимание на опцию noEmit . Мы используем её, так как планируем применять TypeScript только для проверки типов.

Настраиваем TypeScript

В начале файлов .js , в которых вам нужна проверка типов, добавьте комментарий:

Запустите проверку типов. Это можно сделать с помощью команды:

Рекомендуется использовать проверку типов также в инструментах непрерывной интеграции (CI).

Дальше поговорим о документировании кода с помощью JSDoc.

Базовые аннотации

Аннотации параметров функций

Для аннотации параметров функций используйте @param . Его нужно указать в комментариях JSDoc, которые начинаются с двух идущих подряд астериксов.

Документирование кода

JSDoc — инструмент для документирования. Кроме добавления аннотаций типов, вы можете документировать функции.

Потренируемся в документировании.

Документирование параметров

Опциональные типы

Чтобы показать опциональность типа, добавьте после него знак равенства. В примере ниже number= — то же самое, что и number | null | undefined . Такой синтаксис можно использовать только в типах JSDoc.

Документируем опции

Вы можете документировать свойства параметров, например, options.count или options.separator . Эту возможность можно использовать для документирования props в функциональных компонентах React.

Утверждения типов (Type Assertions)

Переменные

Используйте @type , когда пишете инлайн определение для аргументов функций. Это обычно избыточно для констант, так как TypeScript чётко работает с типами. Подход полезен при работе с изменяемыми данными, например, с переменными.

Параметры функций

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

Далее поговорим о выносе определений типов в отдельные файлы.

Импорт определений типов

Импортируем типы

Сложные и переиспользуемые типы лучше определять во внешних файлах. Они имеют расширение .d.ts . Обратите внимание, это должны быть именно файлы TypeScript. Импортировать определения из файлов JavaScript невозможно.

Типы можно импортировать с помощью представленного ниже синтаксиса. Определения должны определяться во внешних файлах с расширением .d.ts , как сказано выше.

Определяем типы во внешних файлах

Ниже представлен синтаксис определения типов во внешних файлах TypeScript. Ещё раз обратите внимание, импортировать определения типов из файлов JavaScript невозможно.

Теперь разберёмся, можно ли определять типы в JavaScript-файлах.

Определение типов в файлах JavaScript

Типы объектов

Для определения типов объектов используйте @typedef . Предпочтительно делать это во внешних файлах с расширением .d.ts . Но вы можете использовать представленный ниже синтаксис и в файлах JavaScript.

Объединение типов

Используйте объединение типов ( | ) для определения двух или более возможных вариантов. Для простоты используйте @typedef .

Как насчёт React?

Определение типов в React

Функциональные компоненты

Функциональные компоненты представляют собой функции. Поэтому вы можете документировать их способами, о которых говорилось выше в разделе о документировании функций. В следующем примере показано документирование с помощью типов объектов.

Подробности о функциональных компонентах можно узнать в курсе по React, который входит в профессию «Фронтенд JavaScript».

Компоненты на классах

Используйте @extends для определения типов props и state . Также для решения этой задачи можно использовать @typedef инлайн или с импортом.

Расширенные возможности

Синтаксис JSDoc не такой выразительный, как TypeScript, но эти инструменты всё-таки похожи. Ниже перечислены некоторые дополнительные возможности TS, доступные в JSDoc.

  • Темплейты — @templates .
  • Возврат значений — @returns .
  • Условия типов — @returns .
  • Функциональные типы — @callback .
  • Перечисления — @enum .

Ещё больше возможностей найдёте в официальной документации.

Резюме

Ниже представлены перечисленные в статье способы работы с аннотациями типов.

Проверка типов JavaScript

Документирование функций

Импорт определений типов (позволяет определять типы во внешних файлах)

Опциональные типы

Анонимные функции

Документирование свойств параметров объектов

Адаптированный перевод статьи Type annotations in JavaScript files by Rico Sta. Cruz. Мнение администрации Хекслета может не совпадать с мнением автора оригинальной публикации.


JavaScript – чрезвычайно гибкий и простой в изучении и работе язык. Крупное активное сообщество и масса преимуществ. Однако и подводных камней не меньше. Большинство из них связаны с избыточной свободой программиста. Сегодня мы взглянем на TypeScript – более строгую версию классического JS.

Миграция без изменения сборки

Проще всего отказаться от JavaScript, когда вы начинаете проект с чистого листа: можно не задумываться о совместимости изменений. Но что, если нужно поддерживать и развивать старые программы? Изменение языка разработки кажется плохой идеей, ведь придётся переписать десятки файлов. Долго, скучно, а главное – легко сломать налаженный процесс сборки проекта.

Но TypeScript является надмножеством JavaScript и полностью с ним совместим. Если скормить TS-компилятору JS-код, он не будет возражать. Миграцию на TypeScript можно проводить постепенно, файл за файлом. Писать новые скрипты на TypeScript, а существующие –переписывать в удобном темпе.

Попробуем добавить TypeScript в имеющийся проект, не меняя конфигурации webpack, gulp или другого сборщика, которым вы пользуетесь.

Шаг 1. Устанавливаем и настраиваем TypeScript

Прежде всего нужно установить TypeScript в приложение (или глобально):

Примечание: в зависимости от проекта вам могут потребоваться также пакеты типов (@types) для различных библиотек. Например, для react-redux нужно установить следующие модули:

Теперь добавим в корень проекта файл tsconfig.json . В нём будут содержаться настройки компилятора, необходимые для конвертации. Возьмите для начала предлагаемую ниже конфигурацию. Она обеспечивает полную совместимость JS и TS синтаксисов.

Чтобы настроить конфигурационный файл под нужды вашего проекта, обратитесь к документации TypeScript.

Теперь в секцию scripts файла package.json добавим команду для компиляции:

При запуске в терминале все файлы с расширением .ts или .tsx будут транслированы в js-файлы. Утилита разместит их по тому же пути, а значит, сборщик сможет работать как раньше, игнорируя ts-исходники.

Примечание: если в проекте нет ни одного .ts -файла, в консоли появится ошибка. Не пугайтесь, команда работает в режиме наблюдения. Как только вы создадите первый typescript-файл, компиляция заработает правильно.

Результат компиляции TypeScript-файла

А теперь пусть начнётся магия 💫. Берём любой JS-файл, и меняем расширение на .ts . Компилятор обрабатывает его без возражений.

Мы только что, не особо напрягаясь, сделали первый шаг для миграции проекта на TypeScript, не внеся ни одного изменения в существующую сборку.

Добавим строгости

Большой прыжок вперёд с технической точки зрения, но в самой разработке ничего не поменялось: ни нового кода, ни преимуществ TypeScript.

Создадим простое приложение, определяющее, может ли пользователь взять ипотечный кредит.

Напишем функцию getSavings , которая будет собирать информацию о доходах и сбережениях клиента:

На основании этих данных функция concedeMortgage будет принимать решение о выдаче кредита:

Чтобы приложение работало нормально, необходимо добавить проверку входных данных. Существует ли значение homeValue , является ли оно числом? Кроме того, нужно убедиться, что функция getSavings() возвращает корректное значение сбережений. Итак, код немного разрастается:

Это выглядит некрасиво, пора воспользоваться преимуществами TypeScript.

noImplicitAny

Добавьте в файл tsconfig.json в секцию compilerOptions новую опцию:

Можно не проверять, являются ли входное значение и результат работы getSavings числами. Мы просто укажем нужный тип. Проверки станут короче:

Теперь можно отловить ошибку типа на стадии компиляции! TypeScript не позволит вызвать функцию concedeMortgage , например, со строковым значением:

К сожалению, значения null и undefined всё ещё допустимы в каждом типе, так что можно безнаказанно делать вот так:

Не переживайте, сейчас мы это поправим.

strictNullChecks

Активируйте опцию компилятора:

Теперь вызов функции с null также приводит к ошибке. Можно убрать все проверки и вернуть concedeMortgage к первозданному чистому виду:

Это была лишь малая часть магии TypeScript. Он способен существенно облегчить работу JavaScript-программиста, не требуя при этом никакой особенной настройки и сложной конфигурации.

Читайте также: