Проверка против запуска: какой роль играет компилятор Go в TypeScript 7 в вашей инструментальной сборке.
Узнайте, что на самом деле ускоряет встроенный компилятор Go в TypeScript 7, почему такие инструменты, как Angular и typescript-eslint, отстают, и как разделить проверку типов от выполнения кода.
Источники: TypeScript 7 Moved Its Compiler to Go. Here’s What Actually Changes
TypeScript 7 заменяет самостоятельно размещаемый компилятор на нативную версию, написанную на Go, причем указанные цифры настолько велики, что могут вызвать путаницу относительно того, что на самом деле становится быстрее. Скорость работы вашего продакшн-JavaScript совсем не меняется; изменения касаются только вашего редактора, инструментов проверки типов в рамках CI и процесса сборки монорепозитория. В то же время Node, Bun и Vite сделали использование компилятора TypeScript необязательным для запуска и преобразования кода. Этот гид разделяет эти аспекты, чтобы вы могли решить, что обновлять, чего ждать, и как организовать инструментарий, в котором проверка и выполнение кода являются двумя отдельными задачами.
Благодаря широкому распространению TypeScript важно сделать его использование правильным. В августе 2025 года GitHub сообщил, что TypeScript стал самым популярным языком среди пользователей, регулярно вносящих изменения, обогнав как Python, так и JavaScript; более 2,6 миллиона человек ежемесячно участвуют в разработке кода на TypeScript. Изменения в основах этой экосистемы влияют на фреймворки, инструменты проверки кода, менеджеры пакетов и редакторы, причем не все они развиваются с одинаковой скоростью.
От самостоятельно размещаемого компилятора к нативному
До версии 7 tsc был программой с самостоятельным запуском. Его исходный код составлял TypeScript, он компилировался в JavaScript, который затем выполнялся в Node для обработки, проверки и генерации кода для проектов других пользователей. Самостоятельное хостингование является традиционным подходом для компиляторов, и такая архитектура помогла языку пройти через десять лет стремительного роста. Однако её ограничением является среда выполнения JavaScript: один основной поток, куча с механизмом сбора мусора, которая никогда не настраивалась для обработки огромных внутренних структур из синтаксических узлов и типов, а также ограниченные возможности для обмена этими данными между процессами.
Ответ Microsoft заключался в портировании, а не в полной переработке. Кодовая база Go намеренно воспроизводит структуру и поведение существующей реализации, поэтому система типов и её семантика должны оставаться прежними. Изменяется лишь основа, лежащая в их основе: нативный машинный код, потоки, способные делиться памятью, и гораздо больше возможностей для параллельной обработки задач. Именно по этой причине Go стал прагматичным выбором; его модель памяти и коллектор мусора позволяют команде переводить существующий код с использованием аналогичных структур данных, вместо того чтобы полностью перепроектировать всё с учётом правил владения.
Опубликованные тесты показывают, что время выполнения полных сборок увеличивается в 8–12 раз:
- Время сборки кодовой базы VS Code сокращается с 125,7 секунд при использовании TypeScript 6 до 10,6 секунд при использовании TypeScript 7.
- Время полной сборки Playwright сокращается с 12,8 секунд до 1,47 секунды.
Фраза «TypeScript работает в десять раз быстрее» является точным кратким описанием этих цифр. Однако её легко неправильно понять, поскольку не указано, что именно работает в десять раз быстрее.
Что становится быстрее, а что — нет
Возьмём небольшой обычный фрагмент кода на TypeScript: интерфейс и объект, соответствующий ему.
interface User {
id: string;
name: string;
}
const user: User = {
id: '42',
name: 'Arthur',
};
Независимо от инструмента, который его компилирует, браузер или сервер в итоге получают обычный JavaScript без информации о типах:
const user = {
id: '42',
name: 'Arthur',
};
Во время выполнения неизвестно, какой компилятор обработал исходный код и на каком языке был реализован этот компилятор. Система видит только генерированный JavaScript, и этот результат остается прежним. Поэтому замена tsc на реализацию на Go никак не влияет на скорость выполнения вашего приложения. Если страница загружается медленно или обработчик API работает с ограниченными ресурсами процессора, TypeScript 7 ничего не изменит в этом отношении.
Положительные эффекты проявляются на ранних этапах разработки, когда TypeScript работает непрерывно: загрузка проектов, вычисление диагнозов, предоставление подсказок и информации о всех ссылках, мониторинг файлов, а также повторная проверка сборки в системах CI. Один показатель хорошо отражает это: раньше для открытия файла с ошибкой в репозитории VS Code требовалось примерно 17,5 секунд до появления первого диагноза; с TypeScript 7 этот процесс занимает менее 1,3 секунды. Новый языковой сервер построен на протоколе Language Server Protocol, может использовать несколько потоков, и Microsoft также сообщает о значительно меньшем количестве неудачных команд языкового сервера и сбоев.
Полезная формулировка звучит так: само приложение не становится быстрее, но работа с ним ускоряется. В крупных кодовых базах или монорепозиториях сокращение времени на проверку типов с нескольких минут до нескольких секунд, а также время на диагностику в редакторе изменяют цикл обратной связи, с которым вы сталкиваетесь в течение всего дня. Это реальное улучшение производительности, хотя ни один пользователь этого не заметит.
Остальное в релизе TypeScript 7
В центре внимания остается нативный компилятор, но несколько подсистем были переписаны с учётом его возможностей.
Параллелизм, который можно настроить
Парсинг, генерация кода и части проверки типов могут выполняться параллельно, а сборка проектов с использованием ссылок позволяет одновременно компилировать несколько проектов, что особенно важно в монорепозиториях. Вы можете явно увеличить количество процессов для проверки типов:
tsc --checkers 8
Или полностью отключите параллелизм для устройств с ограниченными ресурсами или когда вам нужно детерминистичное поведение во время отладки:
tsc --singleThreaded
Отдельный флаг --builders контролирует количество одновременно выполняемых сборок на основе ссылок на проекты. Рассматривайте их как регулировочные элементы, а не как переключатели «максимум всего». Каждый дополнительный рабочий процесс занимает свою часть памяти программы, поэтому CI-сервер с большим количеством ядер, но ограниченной оперативной памятью, может работать медленнее или закончиться нехваткой памяти, если просто соответствовать количеству рабочих процессов количеству ядер. Измеряйте производительность на реальных серверах перед тем, как задавать какие-либо настройки.
Пересозданный режим наблюдения
--watch также был переимплементирован. Сначала команда попробовала более традиционные кроссплатформенные подходы, доступные в Go, но опрос файловой системы оказался слишком ресурсоемким для крупных проектов. В итоге они перенесли идеи механизма отслеживания файлов на C++ из Parcel в Go и создали новый механизм, направленный на более эффективное использование ресурсов в различных операционных системах.
Новые стандартные настройки и удаленные устаревшие опции
TypeScript 7 сохраняет изменения конфигурации, внесенные во время перехода с TypeScript 6:
strictвключен по умолчанию.- Стандартным значением для
moduleтеперь являетсяesnext. typesизначально представляет собой пустой массив, поэтому глобальные пакеты типов больше не загружаются автоматически.target: es5был удален.- Классический механизм разрешения модулей был устранен.
baseUrl больше не поддерживается.tsconfig.json, в котором не вносились изменения с тех времен, когда Internet Explorer был важным фактором развертывания, скорее всего, требует внимания. Изменения в разделе types могут привести к множеству ошибок типа «имя не найдено» для глобальных переменных тестов или встроенных функций Node, пока вы не укажете список пакетов, от которых зависите. Если вы ещё не разобрались с этими стандартными настройками, наш практический руководство по миграции на изменённые стандарты TypeScript 6.0 подробно рассматривает их, причём те же исправления применимы и здесь.
Отсутствующий элемент: стабильный API компилятора
Самым важным моментом является отсутствие у TypeScript 7.0 стабильного программного API. Для многих проектов это важнее любых флагов или значений по умолчанию, поскольку именно оно определяет, смогут ли инструменты, связанные с компилятором, вообще функционировать.
Почему экосистема не может измениться за одну ночь
Вызов компилятора из терминала и создание инструмента на его основе — это совершенно разные подходы. Многие фреймворки, языковые инструменты и линтеры не просто используют бинарный файл напрямую:
tsc
Они загружают TypeScript как библиотеку и запрашивают у неё деревья синтаксиса, разрешенные типы, ответы службы языка и другую внутреннюю информацию компилятора. Замена этого API ожидается в TypeScript 7.1, и до тех пор Microsoft официально поддерживает одновременную установку обеих основных версий. На момент написания этого текста это означает, что многие команды будут использовать нативный компилятор для проверок в командной строке, в то время как их интеграции с редакторами и линтеры продолжат загружать версию, основанную на JavaScript.
Пострадают несколько известных инструментов:
- Проверка типов шаблонов в Angular тесно связана с TypeScript, поэтому полная поддержка редактора в Angular пока должна оставаться с использованием старой службы языка.
- Инструменты для Vue, Astro, Svelte, MDX и других форматов, в которых TypeScript встроен в другой тип файла, сталкиваются с аналогичными ограничениями до появления нового API.
Всё это не является недостатком порта. Так выглядит миграция фундаментального инструмента в реальной экосистеме: движок готов до того, как все добавленные к нему компоненты будут адаптированы.
Четыре способа, которыми инструмент может зависеть от TypeScript
typescript-eslint — хороший пример для этого. Сам ESLint не построен на компиляторе TypeScript, поэтому утверждение о том, что «ESLint стал быстрее благодаря переходу TypeScript на Go», просто неверно. Однако typescript-eslint служит мостом, позволяющим ESLint парсить синтаксис TypeScript и, для правил, основанных на типах, запрашивать информацию о типах в TypeScript. Его текущий парсер по-прежнему использует старый API компилятора, хотя команда разработчиков экспериментирует с нативной реализацией. Разработчики явно готовятся к изменениям, но переход на TypeScript 7 — это не просто увеличение номера версии.
Этот пример показывает важное различие, которое стоит иметь в виду каждый раз, когда кто-то говорит, что инструмент «использует TypeScript». Существует как минимум четыре разных вида взаимосвязей:
- Написан на TypeScript. Сам исходный код инструмента — это TypeScript. Его создатели получают преимущества от более быстрой проверки типов и сборки, но пользователи не замечают никаких изменений.
- Запускает TypeScript. Среды выполнения вроде Node и Bun принимают файлы с расширением
.tsв качестве входных данных без участия инструментаtsc. - Преобразует TypeScript. Инструменты для сборки и транспиляции удаляют типы и переписывают синтаксис, обрабатывая по одному файлу за раз.
- Зависит от семантики TypeScript. Инструменты проверки кода с правилами, учитывающими типы, сервисы языка фреймворков и редакторы нуждаются в компиляторе, чтобы понимать целую программу.
Нативный порт изменяется по-разному для каждой категории. Только последняя из них требует API компилятора, и именно эта категория должна дождаться выхода версии 7.1.
Менеджер пакетов на этапе миграции
pnpm демонстрирует, как взаимодействуют эти категории. Это большой монорепозиторий на TypeScript с множеством пакетов, сложными процессами тестирования и обширной аналитикой в редакторе, что теоретически делает его идеальным кандидатом для использования TypeScript 7. В конечном итоге так и будет. Тем временем его разработчики должны также обеспечивать работу библиотеки typescript-eslint, причем её интеграция с инструментами проверки кода по-прежнему связана с устаревшим интерфейсом компилятора. Цепочка зависимостей выглядит примерно так:
pnpm
↓
typescript-eslint
↓
TypeScript compiler API
↓
TypeScript 6 — for now
Также важно четко определить, с чем столкнутся пользователи pnpm. TypeScript 7 не делает эту команду быстрее:
pnpm install
Установка пакетов — это функция работы pnpm во время выполнения, причем pnpm работает как JavaScript в Node, независимо от того, какой компилятор обрабатывал его исходный код. TypeScript 7 может улучшить процесс разработки pnpm: проверку типов, запуск CI и другие рабочие процессы, основанные на компиляторе. Однако даже такие улучшения появляются с той же скоростью, что и самая медленная важная составляющая в его графе зависимостей. Крупный проект не может быстрее внедрить фундаментальные изменения, чем инструменты, от которых он зависит.
Где преимущества проявляются сразу
Проекты, которым требуется только компилятор в качестве инструмента проверки из командной строки и сервера языка, смогут получить выгоду немедленно. Самым ярким примером является VS Code: огромная база кода на TypeScript, где миллионы разработчиков ежедневно используют инструменты для этого языка. Сокращение времени полной компиляции с более чем двух минут до примерно десяти секунд — это значительное улучшение; сокращение времени ожидания первой диагностики отредактированного кода с примерно семнадцати секунд до чуть более одной — это то, что ощутит каждый.
Playwright, один из проектов Microsoft для тестирования производительности, сокращает время полной компиляции при использовании стандартных настроек с 12,8 секунд до 1,47 секунды. Однако это не означает, что Playwright запускает Chromium быстрее. Это значит, что поддержка и проверка собственного кода Playwright становятся гораздо более быстрыми. Учитывая, что многие инструменты для разработчиков написаны на TypeScript, более быстрая поддержка этих инструментов оказывает положительное влияние на всю экосистему.
Vite уже рассматривает проверку типов и преобразование как отдельные задачи
Vite в основном написан на TypeScript, но при обслуживании или сборке вашего приложения на TypeScript он не вызывает компилятор TypeScript для транспиляции каждого модуля. Современная версия Vite использует специальную систему преобразований и намеренно пропускает проверку типов. В его документации рекомендуется запускать TypeScript отдельно в качестве единоразовой проверки:
tsc --noEmit
или непрерывно во время разработки:
tsc --noEmit --watch
Логика верна. Для преобразования файла достаточно лишь удалить аннотации, переписать несколько конструкций и продолжить. Проверка типов требует знания всей структуры модулей, поскольку изменение в одном файле может нарушить соглашения, установленные в другом. Выполнение обеих операций на одном этапе заставляет быструю процедуру ждать медленной. Поэтому типичный проект Vite имеет два параллельных пути, исходящих из одного источника:
┌── Vite / Oxc ── transform ──> Browser
TypeScript source ──┤
└── TypeScript ───── type-check
С этой точки зрения TypeScript 7 не обязан становиться самым быстрым преобразователем JavaScript, поскольку у Vite уже есть инструмент, оптимизированный для этой задачи. TypeScript может сосредоточиться на том, что требует понимания всей программы, и эта работа теперь выполняется гораздо быстрее. Если вы используете такую конфигурацию сегодня, одним из практических последствий является то, что ошибка типа не останавливает сервер разработки; убедитесь, что команда tsc --noEmit выполняется в CI или в хуке перед публикацией, чтобы ошибки не проскочили.
Инструменты JavaScript, написанные не на JavaScript
Здесь наблюдается более общая тенденция. Текущий процесс сборки Vite использует Rolldown, причем как Rolldown, так и Oxc написаны на Rust. esbuild много лет назад выбрал Go. Bun реализует большую часть своей структуры на Zig. Теперь к ним присоединился и TypeScript с использованием Go.
Это не критика JavaScript. Публичные интерфейсы по-прежнему кажутся естественными для разработчиков JavaScript и TypeScript, в то время как тяжелые по вычислительным ресурсам операции парсинга, разрешения и анализа выполняются в виде нативного кода. Разные слои имеют разные требования, и TypeScript 7 является наиболее заметным недавним примером выбора языка реализации для каждого слоя.
Среды выполнения, которые работают с TypeScript без tsc
Аналогичное разделение происходит и на уровне сред выполнения. Традиционная картина проекта на TypeScript представляла собой прямую последовательность от исходного кода к компилятору, затем к JavaScript и, наконец, к Node:
TypeScript
↓
tsc
↓
JavaScript
↓
Node.js
В реальных проектах всегда было больше этапов, но основная идея оставалась прежней: Node выполнял JavaScript, поэтому TypeScript сначала нужно было преобразовать в JavaScript. Сегодня это можно делать напрямую:
node server.ts
Важным моментом является то, что Node не запускает компилятор TypeScript. Его встроенная поддержка намеренно минимальна: он удаляет синтаксис TypeScript, который можно удалить, и выполняет оставшуюся часть кода. Он не осуществляет проверку типов, а синтаксис, требующий генерации реального JavaScript (а не просто удаления аннотаций), не попадает под действие этой процедуры удаления. Типизированное объявление вроде этого:
const port: number = 3000;
фактически превращается в следующее перед выполнением:
const port = 3000;
Ключевым словом является «Erasable». Структуры вроде enum, namespace с значениями во время выполнения или свойства параметров конструктора генерируют JavaScript, которого не было в исходном коде, поэтому простое удаление элементов не может с ними справиться. TypeScript предлагает опцию компилятора erasableSyntaxOnly для отметки таких структур, если вы хотите, чтобы ваш код оставался совместимым с процедурой удаления типов; ознакомьтесь с документацией Node и TypeScript для вашей версии, чтобы узнать точное поведение.
Эта возможность существовала ещё до Node 26, поэтому прямая обработка TypeScript не должна рассматриваться как функция Node 26. Node 26 приносит собственные изменения: по умолчанию включён Temporal, используется новая версия V8, произошло ещё одно значительное обновление Undici, а также проводится стандартная очистка после выпуска крупной версии, но это уже отдельная тема. Для данного обсуждения важен лишь направление развития: Node всё чаще рассматривает TypeScript как входные данные, которые можно обрабатывать напрямую, без необходимости сначала запускать tsc для генерации JavaScript.
Bun рассматривает TypeScript как обычные входные данные
Bun, который до сих пор находится в версионной линии 1.x, с самого начала работал именно так. Запуск файла TypeScript заключается просто в следующем:
bun server.ts
Загрузчик Bun удаляет и преобразует синтаксис TypeScript перед выполнением с использованием собственных инструментов. И, как и раньше, транспиляция не включает проверку типов. Следовательно, идеальный рабочий процесс в Bun состоит из двух команд:
tsc --noEmit
bun server.ts
Первый вопрос отвечает на вопрос «Удовлетворяет ли этот программный код системе типов?» Второй вопрос отвечает на вопрос «Может ли эта программа запуститься?» Современный Node поддерживает такое же разделение:
tsc --noEmit
node server.ts
В обоих случаях время выполнения никогда не ждет проверки типов, а проверка типов никогда не нуждается в создании файлов с результатами. Имейте в виду, что проект, запускаемый таким образом, не имеет этапа сборки для случайного выявления ошибок типов; если проверка не встроена в CI, она просто не будет выполняться.
Задача TypeScript — понимание программ
В течение многих лет рабочий процесс сводился к одной цепочке операций, где компилятор находился непосредственно между написанием и запуском кода:
Write TypeScript
↓
Compile TypeScript
↓
Run JavaScript
Современные инструменты всё чаще представляют собой две ветви, исходящие из одного источника: одна для понимания и проверки, другая — для преобразования и выполнения:
┌── TypeScript ── understand and check
TypeScript source ────────┤
└── Runtime / bundler ── transform and execute
Vite может использовать Oxc для преобразования кода, в то время как tsc проверяет его. Node сам удаляет синтаксис, предназначенный для удаления. Bun имеет свой собственный загрузчик. Ни один из этих инструментов не требует TypeScript 7 или tsc для запуска вашего приложения. Именно поэтому нативный компилятор по-прежнему важен: наиболее характерная функция TypeScript больше не заключается в быстром преобразовании файла .ts в файл .js, что уже хорошо справляются другие инструменты. Его истинная ценность заключается в решении задач, связанных с всем программным кодом, таких как:
- Совместима ли эта величина с контрактом, к которому она передается?
- Не нарушил ли рефакторинг работу какого-либо компонента в другом пакете?
- Верна ли эта генерическая ограничение?
- На что указывает этот символ и где ещё используется этот тип?
- Что должен предложить редактор в качестве автодополнения именно здесь?
Чтобы удовлетворить эти потребности, требуется гораздо больше контекста, чем простое удаление : string из строки, и именно анализ всей программы — это то, что сделало порт на Go в разы быстрее. Чтобы узнать больше о работе TypeScript нативно в этих инструментах, ознакомьтесь с нашим руководством по миграции на компилятор TypeScript для Go и нативную реализацию.
Основные выводы
- TypeScript 7 — это порт существующего компилятора на Go, а не переработка самого языка; генерируемый JavaScript и производительность приложения при выполнении остаются прежними.
- Преимущества проявляются во время разработки: полные сборки обычно выполняются в 8–12 раз быстрее, диагностика в редакторе происходит гораздо быстрее, а сервер языка становится более стабильным.
--checkers, --builders и --singleThreaded с учётом реальных ограничений памяти в CI, а не просто максимизируйте количество рабочих процессов бездумно.typescript-eslint могут заставить вас использовать TypeScript 6 для некоторых интеграций; одновременная работа обеих версий поддерживается.tsconfig.json на наличие новых стандартных значений и устаревших опций (strict, module, types, целевая версия ES5, классический способ разрешения имён, форматы AMD/UMD, baseUrl). tsc --noEmit в процессах CI.