Журнал / Польза

Что такое типизация, зачем она нужна и чем так хорош TypeScript

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

Что значит «типизация»?

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

Таким образом, есть четыре взгляда на типизацию.

Ограничение переменных. Мы можем смотреть на тип как на ограничение переменных. Если тип — это функция, то её можно вызвать. Если тип — это объект, то у него есть какое-то поле. Если тип — это массив, то у него есть длина. И так далее.

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

Описание поведения сущности. Тип может описывать некий класс, иметь методы и определённые поля. Благодаря такому типу мы понимаем, как класс себя ведёт.

Пометка на значении. Такой подход называют номинативной типизацией — когда мы вешаем некий ярлычок на существующее значение.

Какие виды типизации существуют?

Статическая и динамическая типизация

Статическая типизация означает проверку типов перед запуском программы, динамическая — проверку типов, когда программа уже запущена.

C#, C++, Java, Go и TypeScript — статически типизированные языки. Если в одном из этих языков вы создадите число и попытаетесь проводить с ним операции как с функцией, вы получите ошибку во время компиляции, а программа не станет запускаться — она даже не дойдёт до этой стадии, потому что ошибка типизации будет обнаружена перед исполнением.

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

Сильная и слабая типизация

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

Java, C#, Scala, Python, TypeScript — строго типизированные языки. Сильная типизация не даёт возможности смешивать разные типы переменных. Если вы присвоите числовой тип, то добавить, например, строчный уже не получится.

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

А зачем вообще нужна типизация в вебе, если сайты на JavaScript и без этого хорошо работали с 90-х годов?

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

JavaScript не был предназначен для построения каких-то крупных приложений — это изначально был больше язык сценариев. Он использовался для создания простого интерактива и анимаций: например, чтобы запустить снежинки по экрану на сайте.

Поэтому с ростом веба, с появлением первых приложений со сложной логикой, например Gmail, стали вылезать проблемы.

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

foto1

Приходится запоминать сигнатуры функций. Часто в JavaScript, когда у нас есть большая функция, мы можем понять, что она делает, только просмотрев весь её код. Хотелось бы при вызове уже примерно понимать, какие в функции должны быть аргументы и что функция возвращает.

Неявное приведение типов. Когда true складывается с массивом, мы ожидаем получить не какую-то «химеру», а уже существующий элемент в JavaScript. Этот процесс регулируется огромными таблицами приведения типов — как одни типы превращаются в другие в рантайме. Но их тяжело читать, а некоторые переходы неочевидны.

Интересно. А TypeScript может решить эти проблемы?

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

Вот чем он хорош:

  • Предупреждает об ошибках до запуска кода.

  • Позволяет сократить время на написание простых тестов — на TypeScript можно не писать unit-тесты для проверки типов.

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

  • Запрещает складывать массивы с объектами из-за повышенной строгости типизации.

  • На TypeScript легко перейти, зная JavaScript.

Но имейте в виду, что:

  • Типов TypeScript нет ни в браузере, ни в Node.js.

  • TypeScript ничего не знает о рантайме, поэтому все типы исчезают из конечного кода (концепция стираемых типов).

  • Несмотря на все свои плюсы, TypeScript не может сделать больше, чем JavaScript.

  • TypeScript не защитит вас от ошибок в бизнес-логике или таких причуд JavaScript, как неявное приведение типов к строке в интерполированных строках.

TypeScript — это не волшебный язык, и вообще волшебных языков в программировании не бывает.
Александр Николаичев, разработчик интерфейсов во внутреннем облаке Яндекса

shema1

Очень просто. Нужно всего лишь выполнить две короткие команды: установку и запуск. TypeScript устанавливается как обычный npm-пакет. Пишем команду npm i -D и устанавливаем TypeScript в devDependencies, а команда tsc запустит компилятор.

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

shema2

Что тут интересного:

  • target — указываем версию JS (в нашем случае ES5), чтобы превращать TypeScript-файлы в JavaScript.

  • allowJs — разрешаем js-файлы — это важно на этапе миграции. После окончания миграции их можно запретить.

  • strict — включаем строгий режим TypeScript, который, соответственно, включает строгий режим в JavaScript и некоторые дополнительные проверки.

  • outDir — указываем выходную папку для собранных файлов.

  • sourceMap — это служебные файлы, содержащие исходники проекта для отладки скомпилированного кода.

  • esModuleInterop — настройка, которая разрешает писать import вместо require. Казалось бы, мелочь, но если вы много пишете для Node.js или браузера, хотите добиться какой-то консистентности синтаксиса кода и юзать import, эта настройка очень вас выручит. Ещё вам потом легче будет переходить на нативные модули в ноде.

На сайте TypeScript есть песочница — поле для экспериментов. Выберите версию компилятора, настройки компиляции и тренируйтесь в написании кода.