Главная / Статьи

TypeScript 7 и порт на Go: более быстрые сборки, оптимизация использования памяти и улучшения в редакторе.

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

Издатель: REACTAPP.TOP8 мин чтения1789 слов

Источники: TypeScript 7 Is Here — And It Changes Much More Than the Compiler

Любой, кто использует TypeScript уже много лет, знает этот ритм: пишется код, редактор некоторое время его обрабатывает, TypeScript анализирует проект, затем запускается tsc, и снова приходится ждать. В крупном монорепозитории эта пауза бывает настолько долгой, что хватает времени на кофе. Всё это не означает, что инструмент плохо спроектирован. Его система типов и средства разработки стали настолько мощными, что могут справляться с очень большими кодовыми базами, и именно поэтому он стал настолько важным в мире JavaScript. Однако такая мощность имела свою цену: по мере расширения проектов компилятор и сервер языка превращались в препятствие для производительности.

TypeScript 7.0 — это ответ от Microsoft, и примечательно то, что основное изменение заключается не в появлении нового оператора, ключевого слова или синтаксической техники. Речь идет о движке, лежащем в основе. Компилятор TypeScript раньше писался на самом TypeScript, что создавало приятную рекурсивную структуру, хорошо функционировавшую, но требовало, чтобы компилятор работал в рамках модели выполнения JavaScript. В версии 7 Microsoft перенес компилятор на язык Go, создав нативную реализацию, способную использовать современное оборудование и возможности параллельных вычислений.

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

Цифры скорости

Основной показатель говорит о в десять раз большей скорости. Тесты Microsoft показывают, что полные сборки обычно выполняются в 8–12 раз быстрее в зависимости от проекта, причем эти тесты проводятся на крупных реальных кодовых базах, а не на синтетических микротестах.

Время сборки даже не является самым впечатляющим результатом, поскольку ускоряется также сервер языка. В примере Microsoft с использованием кодовой базы VS Code время открытия файла, содержащего ошибку, сократилось с примерно 17,5 секунд до появления первой ошибки до менее чем 1,3 секунды. Это совершенно иной уровень работы, и в крупных репозиториях это имеет большее значение, чем сокращение нескольких сотен миллисекунд времени сборки в производственной среде.

Использование всех ядер

Современные процессоры имеют множество ядер, в то время как tsc традиционно использовал только одно. TypeScript 7 гораздо эффективнее их использует: парсинг, проверка типов и генерация кода могут выполняться параллельно там, где это возможно. Кроме того, он добавляет несколько экспериментальных параметров настройки:

--checkers
--builders
--singleThreaded

Первые два параметра позволяют более точно контролировать распределение параллельных задач, а параметр --singleThreaded отключает параллелизм по мере необходимости, например при отладке поведения компилятора или при работе в ограниченных условиях.

Больше всего выгоды получат монорепозитории. Представьте репозиторий с каталогом apps:

apps/
  web/
  admin/
  mobile/

и каталог пакетов:

packages/
  ui/
  api/
  config/
  utils/
  domain/

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

Память

Производительность — это не только время работы процессора. Большие проекты на TypeScript могут потреблять несколько гигабайт ОЗУ, особенно когда сервер языка работает вместе с редактором, браузером, Docker и серверами разработки. Опубликованные Microsoft тесты показывают снижение потребления памяти примерно на 6–26% в нескольких крупных проектах:

  • Bluesky: примерно на 26% меньше
  • VS Code: примерно на 18% меньше
  • tldraw: примерно на 15% меньше
  • Playwright: примерно на 11% меньше

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

Новый сервер языка

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

В TypeScript 7 появился новый сервер языка, построенный на протоколе Language Server Protocol, использующий нативную реализацию и многопоточность. Команда продолжает расширять его функционал: появились инструменты вроде кодовых линз, подсказок внутри кода, семантического выделения, сортировки импортов и удаления неиспользуемых импортов, а также автоматические импорты, возможность перехода к определению в исходном коде, редактирование JSX и автодополнение тегов. Цель заключается не просто в ускорении работы tsc: вся цепочка от ввода кода до получения обратной связи становится быстрее, и это, пожалуй, главное преимущество.

Детерминистичный вывод при параллелизме

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

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

function foo(condition: boolean) {
  return condition ? 100 : 500;
}

Это может привести к такому заявлению:

export declare function foo(
  condition: boolean
): 100 | 500;

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

Это не версия с новыми функциями

Те, кто ожидал чего-то подобного:

type NewSuperPower<T> = ...

Из-за большого количества новых функций языка TypeScript 7 может показаться на первый взгляд не таким впечатляющим. Большинство усилий было направлено на развитие инфраструктуры, а не на добавление новых возможностей типовой системы. Команда годами создавала основу для следующего поколения TypeScript, и теперь оно уже существует. План развития предусматривает дальнейшую работу над новыми функциями, улучшение удобства использования, повышение производительности и появление нового API-интерфейса компилятора после версии 7.0. Эта версия скорее можно рассматривать как начало новой эры, чем как конец предыдущей.

Замечания для создателей инструментов

Здесь всё становится интереснее для тех, кто разрабатывает инструменты. TypeScript 7.0 не поставляется с старым API компилятора, и команда ожидает, что в версии 7.1 будет представлен новый интерфейс. Это имеет большое значение, поскольку большая часть экосистемы не просто запускает команду tsc — линтеры, компиляторы фреймворков, сервисы языка и инструменты сборки взаимодействуют с TypeScript программно.

Это одна из причин, по которой TypeScript 6 и 7 пока могут сосуществовать параллельно. Microsoft ввела @typescript/typescript6, чтобы облегчить переход: проект может сохранить версию 6 для инструментов, которым всё ещё нужен её API, одновременно используя компилятор версии 7 отдельно. Обновление компилятора не всегда так просто, как изменение одной строки:

{
  "devDependencies": {
    "typescript": "^7.0.0"
  }
}

В крупных экосистемах компилятор является инфраструктурой, а у инфраструктуры есть зависимости.

Ещё одно ограничение касается фреймворков и инструментов, которые включают TypeScript в свои собственные процессы компиляции или работы с языковыми сервисами. Команда называет Vue, MDX, Astro, Svelte и Angular рабочими средами, в которых поддержка новой архитектуры языковых сервисов всё ещё находится на стадии развития, причём отсутствие стабильного программного API объясняет это явление. Простое приложение на React и TypeScript может быть переведено с минимальными проблемами. Однако при сложной интеграции с фреймворком, использовании плагинов компилятора или плагинов языковых сервисов путь становится сложнее. Перед обновлением любого крупного производственного репозитория стоит это проверить.

TypeScript 6 как ступень к обновлению

TypeScript 6 никогда не был просто версией, предшествовавшей 7. Его специально создали в качестве моста между версиями. Несколько старых опций компилятора были отмечены как устаревшие и полностью устранены в версии 7, поэтому команда рекомендует устранить их до перехода на новую версию. Использование промежуточной версии, как показано ниже, предпочтительнее, чем рассматривать версию 7 как самостоятельное обновление:

TypeScript 5.x
      ↓
TypeScript 6
      ↓
TypeScript 7

Любые предупреждения о устаревании, генерируемые проектом в TypeScript 6, заслуживают внимания. Фактически это уведомления о миграции, приходящие из будущего.

Почему важен цикл обратной связи

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

type something
↓
autocomplete appears
↓
you navigate to a definition
↓
you rename a symbol
↓
you save
↓
CI runs
↓
the project gets type-checked

TypeScript участвует в каждом этапе, и его роль усиливается по мере развития приложений. Задержка в 100 мс не имеет значения, но задержка в 10 секунд — уже имеет значение; ожидание в 30 секунд меняет способ работы человека, а проверка кода с помощью CI в течение пяти минут влияет на работу всей команды. Поэтому основной особенностью TypeScript 7 является не в десятикратно более быстрой компиляции, а в сокращении времени между написанием кода и пониманием того, верен ли он.

Попробовать

Для нового проекта TypeScript 7 определенно стоит рассмотреть. Для существующего проекта более осторожный подход более уместен. Начните с установки его в качестве зависимости для разработки:

npm install -D typescript@7

Затем выполните проверку типов без вывода:

npx tsc --noEmit

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

  1. Ошибки компилятора
  2. Устаревшая конфигурация
  3. Совместимость инструментов сборки
  4. Интеграция с ESLint
  5. Интеграция с фреймворком
  6. Поведение IDE
  7. Производительность CI
  8. Потребление памяти

В крупном монорепозитории проведите тестирование до и после изменений с использованием чего-то вроде:

time npx tsc --build

Сравните полученный результат с текущей версией TypeScript. Основное внимание не должно уделяться только конечной цифре — важна вся совокупность элементов опыта разработки.

Перестройка основ

TypeScript 7 выделяется среди инструментов для фронтенда тем, что команда вместо того, чтобы добавлять новые функции к существующей архитектуре, решила полностью перестроить её основу. Самому языку переосмысления не требовалось, но инфраструктуре — да. Время выбора также оправдано: с появлением крупных проектов на JavaScript, распространением монорепозиториев, использованием типобезопасных API повсюду, более умных редакторов, инструментов кодирования на основе ИИ, требующих семантических данных, и ожиданий со стороны разработчиков почти мгновенных ответов. Компилятор, достаточно быстрый для приложения 2015 года, не обязательно сможет справиться с монорепозиторием 2026 года.

Проще говоря, в этом обновлении признается, что старый дизайн работал, но современное программное обеспечение вышло за его рамки. Вместо того чтобы отказаться от уже понравившейся разработчикам системы типов, команда пересоздала то, что находится в её основе. По этой причине это обновление имеет большее значение, чем может показаться по списку видимых функций. Оно служит основой для дальнейшего развития TypeScript, а также делает инструмент tsc более быстрым. Если обещанные преимущества распространятся на весь экосистему, самые интересные функции TypeScript могут даже не появиться в версии 7 — они могут стать практически применимыми только благодаря тому, что версия 7 достаточно быстра для их реализации.

Главной темой является параллелизм; за ним стоят нативная обработка, сниженное потребление памяти, новый языковой сервер, детерминированный результат компиляции и основа для будущих инструментов. Для тех, кто поддерживает крупные приложения на TypeScript, это, пожалуй, ценнее, чем ещё один инструмент для работы с типами.