Использование возможностей TypeScript в JavaScript без написания TypeScript-кода
Я — большой любитель 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-репозиторий, в котором можно найти примеры кода, использованные в этой статье.
Уважаемые читатели! Как вы относитесь к идее проверки типов в JS-коде с использованием возможностей TypeScript?
How to Add TypeScript to a JavaScript Project
dor sever
I love writing code. And I want to be really good at it. But somehow, writing JavaScript has never been my strong suit.
No matter how much I practiced, the same mistakes kept appearing in production: cannot read property <> of undefined exceptions, the famous [Object object] string, and even function calls with an invalid number of parameters.
What’s more, most of the codebases I was working on were really large JavaScript ones. So here is a nice diagram of how it felt to be me:
We can do much better!
In this post, I’ll avoid explaining why TypeScript is awesome (and it is), and focus on the tasks you need to complete if you want to migrate your vanilla JavaScript project to a mixed TypeScript project.
By the end of the post, you will be a happier person and will be able to answer the following questions:
- How can I add types to my JavaScript project?
- What is TypeScript?
- How can I use TypeScript in a JavaScript project?
- What are the steps to convert a JavaScript application to support TypeScript?
- How can I take care of build & packaging?
- How can I take care of linting?
- How can I “sell” TypeScript to my organization and developers?
How can I add types to my JavaScript project?
Vanilla JavaScript does not support types at the moment, so we need some sort of abstraction on top of JavaScript in order to do so.
Some common abstractions are using Facebook’s static type-checker called flow and Microsoft’s language called : typescript .
This blog post will examine the usage and addition of TypeScript to your JavaScript project.
What is Typescript?
TypeScript is a typed superset of JavaScript that compiles to plain JavaScript.
If you know javascript, you are more than half way there.
TypeScript consists of a few parts. The first is the TypeScript language — this is a new language which contains all JavaScript features . Check out the specs for more information.
The second is the TypeScript compiler, tsc (the type system engine) which is a compilation engine that builds ts files and yields js files.
Hello world in TypeScript
As an example, these are the steps you need to take to write your first TypeScript application:
- install TypeScript with npm i typescript
- create a folder called example and cd into it (in your terminal)
- create a file called hello.world.ts
- write the following code in it:
and then save it.
5. run the tsc command to run the TypeScript compiler on the current folder
6. notice that you got a hello.js file that you can now run 🙂
7. run node ./hello.js
How can I use TypeScript in a JavaScript project?
There are couple of strategies for doing this «migration» (company-wise and code-wise). I’ve listed them below by their «cost» and by how much value they provide.
I would suggest starting with «application TS support» and moving forward after you have proved the value to your development team.
The typescript migration process, iterate through the process only if you prove value.
The «small step for man» approach — Adding TS support for existing applications
One small step for a developer. types are wonderful 🙂
My first suggestion is to create a mixture of the two languages in a single project, and then write all “future” code in TypeScript.
The combination of two languages in a single project sounds pretty awful at first, but it works quite well since TS was built for gradual usage. At first it can be used just as JS with .ts files and weird import lines.
In this strategy, we will be compiling the migrated TypeScript files and just copying the JavaScript files to an output folder.
The huge benefit of this approach is that it allows a gradual learning curve for the development team (and for you) with language and it’s features. It also gives you hands-on experience and insight into its pros and cons.
I highly recommend starting from this step and then iterating on it with your team before moving forward. For a quick “how to do this”, scroll down to The steps to convert a javascript application to support typescript part.
The open for business approach — Adding TS support for existing libraries.
After you have some hands on experience with TS and your development team agrees it’s worth moving forward, I suggest converting your in-house libraries and modules to support TS.
This can be done in two ways:
The first way involves using declaration files. A simple addition of d.ts files helps the TS compiler type-check existing JavaScript code and gives you auto-completion support in your IDE.
This is the «cheapest» option, as it doesn’t require any code changes to the library at all. It also gives you maximum power and types support in your future code.
The second way is to perform a full re-write of TypeScript, which might be time-consuming and error-prone. I would advise against it, unless it proves ROI worthy to your team.
The skeleton — a step towards the future
Typescript skeleton is the way to ensure a bright future!
I assume most developers are «lazy» and usually start their application by copying from a skeleton (which usually contains logging, metrics, configuration, and so on).
This step helps you navigate your way into a bright future, by creating an «official» skeleton for your company. It will be 100% TS, and deprecates the old JS skeleton if one exists.
This typescript-node-starter is a really good first project to start with.
The all in approach — Converting a full codebase from JS into TS
I’m all in! Let’s make all things typed!
This option requires a total rewrite from JavaScript code to TypeScript.
I would recommend doing this as a final step in the TS migration process since it requires a total application re-write and deep knowledge of TypeScript and it’s features.
You can do such a rewrite (it’s a long process) in the following manner:
- Define clear types for your application business logic, API, & HTTP’s
- Use @types packages for all the libraries in your package.json . Most of the libraries out there support TS, and in this process I suggest migrating them one by one (by just adding @types/<package_name> in your package.json file).
- Convert your application logical components in order of their importance. The more unique the business logic, the better.
- Convert the IO parts of your application, database layers, queues and so on.
- Convert your tests.
Keep in mind that there are automated tools designed to ease this process, for example ts-migrate from the Airbnb team.
It tackles this problem from a different perspective, and converts all files to TypeScript. It also allows gradual improvements (like mentioned in the steps above) while the entire codebase is TypeScript from day one.
How to convert a JavaScript application to support TypeScript.
Install typescript
by running : npm install typescript .
Typescript config file
Add a typescript config file, which can be created using the tsc —init command in you CLI.
Here is an example of how our initial config looked:
A few things to notice above:
- We read all the files in the src or test or config directory (using the include flag).
- We accept JavaScript files as inputs (using the allowJs flag).
- We emit all of the output files in build (using the outDirflag ).
Create your first .TS file in your project
I recommend starting by adding a simple TypeScript file (or changing a really simple JS file to a TS one) and deploying. Take this migration one step at a time.
Take care of your package.json file
Here is how our package.json looks before and after:
As you can see, most of the changes were about adding the prefix dist to most of our build commands. We also added a build-dist script that compiles our codebase and moves all files to a dedicated folder called dist .
Add source-map-support
One of the big issues when adding TypeScript to your project is that you are adding a layer of indirection between the code you write and the code that actually runs in production (since .ts is transpiled to .js in run time).
For example, imagine the following TypeScript program:
When we run it, it will throw the following stack-trace:
Wait! but we only have 2 lines in our typescript code!
This is problematic since our code-base contains only .ts files. And since most production code contains hundreds of lines, it will be really time-consuming translating these numbers and files properly.
Luckily for us, there is a solution for this called source-map-support!
This allows us to ensure that stack-traces will have proper .ts file names and line numbers like we are used to 🙂
This can be done by running npm install source-map-support and then adding the following line in the first lines of your application:
The code now looks like this:
And when we compile it we run tsc —sourcemap hello.ts . Now we get the following stack-trace which is awesome 🙂
In recent versions of nodejs , this is supported natively by using the —enable-source-maps flag.
How to take care of your build (Travis) & packaging
Let’s just examine the before and after changes on our build configuration file.
This is how our .travis file looked before (simplified edition):
Simplified .travis before typescript
And this is how it looked after:
Simplified .travis after typescript
Notice most changes concern «packaging» to the tar.xz file and running the build-dist command before accessing the dist folder.
How can I take care of linting?
There are a couple of linting solutions available.
The first solution we used was tsfmt – but then we decided against it later on because it requires you to maintain two separate configurations for your project (one for TypeScript using tsfmt and a separate one for JavaScript using eslint ). The project also looks deprecated.
We then found TSLint which redirected us to the eslint plugin for TypeScript. We then configured it as follows:
This was our eslintrc.js :
Which we configured to run using a lint-fix command in our package.json which looks as follows:
How to «sell» typescript to your development team
I believe one of the most critical aspects of introducing TypeScript to your organization is the «pitch» and how you present it to your development team.
Here is the presentation we presented internally which revolved around the following topics:
- Explain why we think TypeScript is awesome
- What is TypeScript
- Some basic code examples. The main point in this part is not to «teach» 100% TypeScript, since people will do that on their own. Instead, give people the feeling that they can read and write TypeScript, and that the learning curve is not so hard.
- Advanced code examples, like Union types and Algebraic data-types which provide enormous values to a JS developer. This are a real treats, on top of typed-language and the compiler that will attract your developers to it.
- How to start using it. Encourage people to download the vs-code IDE and to add an annotation (//@ts-check) so they can start seeing the magic! In our company, we prepared in advances some really cool mistakes that ts-check catches, and we did a live demo (2-3 minutes) to show how fast the TypeScript compiler can help them using JS docs with type annotations or ts-check ).
- Deep dive into some features. Explain ts.d files and @types packages which are some of the things you will encounter really early in your TypeScript codebases.
- Live PR’s from your work. We showed the PR we created early on, and encouraged people to review it and try it out for themselves.
- Share some cool resources. There is a lot of content online, and it’s hard to figure out good from bad. Do your teammates a solid and dig deeper and try to find quality content about the tools you use and need. Scroll down to the conclusion for my resources.
- Create a public pull request . I recommend trying to get as much support as possible for its approval.
10. Create a positive buzz in your organization about the change!
I highly recommend tweaking this list according to your team, standards, and time-constraints.
Conclusion
Typescript is super awesome! If you are writing production grade software and the business requirements and availability are high, I strongly encourage you to give typescript a try.
Just remember to take it one step at a time. New languages and frameworks are hard, so take the time to learn and to educate yourself and your team before pushing this process forward.
Create a short feedback loop and value proposition. It’s hard to «sell» a new language to your team and management as it takes time and resources.
So design your migration process with short feedback loops, and try to define clear KPI’s (fewer bugs in production, easier refactoring times, and so on) and make sure the value proposition for your use-case is constantly justified until it becomes the de-facto standard.
Make learning resources readily available. I really enjoyed this talk about TypeScript first steps and this blog post about incremental migration to TypeScript.
Also, don’t miss out on the deno project and the ts-node project. I’m super excited and looking forward to using them soon.
JS Projects Utilizing TypeScript
The type system in TypeScript has different levels of strictness when working with a codebase:
- A type-system based only on inference with JavaScript code
- Incremental typing in JavaScript via JSDoc
- Using // @ts-check in a JavaScript file
- TypeScript code
- TypeScript with strict enabled
Each step represents a move towards a safer type-system, but not every project needs that level of verification.
TypeScript with JavaScript
This is when you use an editor which uses TypeScript to provide tooling like auto-complete, jump to symbol and refactoring tools like rename. The homepage has a list of editors which have TypeScript plugins.
Providing Type Hints in JS via JSDoc
In a .js file, types can often be inferred. When types can’t be inferred, they can be specified using JSDoc syntax.
JSDoc annotations come before a declaration will be used to set the type of that declaration. For example:
You can find the full list of supported JSDoc patterns in JSDoc Supported Types.
The last line of the previous code sample would raise an error in TypeScript, but it doesn’t by default in a JS project. To enable errors in your JavaScript files add: // @ts-check to the first line in your .js files to have TypeScript raise it as an error.
If you have a lot of JavaScript files you want to add errors to then you can switch to using a jsconfig.json . You can skip checking some files by adding a // @ts-nocheck comment to files.
TypeScript may offer you errors which you disagree with, in those cases you can ignore errors on specific lines by adding // @ts-ignore or // @ts-expect-error on the preceding line.
To learn more about how JavaScript is interpreted by TypeScript read How TS Type Checks JS
Как использовать аннотации типов в файлах 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. Мнение администрации Хекслета может не совпадать с мнением автора оригинальной публикации.