Тестування продуктивності компілятора Go у TypeScript 7 на реальному додатку Next.js.
Практичне порівняння часу виконання команди tsc check у TypeScript 6 та 7 на реальному кодовому базі Next.js, включаючи проблему несумісності у CI та рекомендації щодо оновлення.
Ті самі 412 файлів, перевірені двічі під двома різними версіями компілятора. За використанням TypeScript 6 перевірка зайняла 3,8 секунди. За використанням TypeScript 7 — 0,41 секунди. Функціонально типовий перевірювач залишається тим самим.
Оприлюднені Microsoft показники стосуються прискорення в 8–12 разів, виміряного у VS Code. Важливим тут є те, що повідомляє команда tsc --extendedDiagnostics у конкретному репозиторії. CI-завдання, яке раніше затримувалося через невдалий крок генерації Prisma, не стане в десять разів швидшим лише через прискорення типового перевірювача — лише цей етап стане швидшим. Усі наступні етапи процесу залишаться такими ж повільними.
Відкрийте термінал.
Пропустіть команду next dev. Переходьте безпосередньо до самого перевірювача та запускайте його з кореня проекту:
pnpm exec tsc --noEmit --extendedDiagnostics
Зверніть увагу на значення Check time, яке він виводить. Цей єдиний рядок — єдина показник, який варто відстежувати тут аж до кінця.
Microsoft випустила TypeScript 7.0 8 липня 2026 року. Сама система типів не змінилась, а бінарник компілятора все ще називається tsc, але внутрішньо це тепер порт компілятора на мову Go. У таблиці з оголошення про версію 1.0 показано, що час перевірки у VS Code знизився з 125,7 секунд до 10,6 секунд. Це число стосується власної кодової бази Microsoft, а не типового проекту Next.js.
Насправді корисним є еквівалентний показник для невеликого додатку Next.js з чотирма маршрутами, який вже тестується за всіма іншими критеріями, а також додатковий показник: скільки коштує команда next build, коли використовується новий інструмент перевірки. Не менш важливим є документування типу помилок, які з’являються, коли автоматизована система pull request припускає, що „швидше“ та „функціонує інакше“ означають одне й те саме.
Післяобідній CI збрехав щодо помилки типу
typescript до версії 7 у додатку для створення рахунків-фактур, оскільки у одній з статей обіцяли 10-кратне прискорення. Система CI значно швидше показала зелений статус. Надихнуті цим, рецензенти схвалили та об’єднали код допоміжної функції branded-id, яка, як виявилося, не працювала на локальному комп’ютері одного з колег через проблеми з перевіркою типу.
Допоміжний скрипт компілювався без проблем на CI лише тому, що CI все ще отримував версію typescript 6 через залежність у кореневому просторі роботи. На локальній машині, у свою чергу, була встановлена версія 7 безпосередньо. Сама система типів не змінилася — у цьому й полягає суть твердження Microsoft — але файл tsconfig на CI прив’язував typescript до псевдоніму пакета @typescript/typescript6, який залишився від запису про перевизначення, доданого під час тестового періоду та так і не видаленого.
Отже, справжньою проблемою не було те, що TypeScript 7 поводився інакше. Проблемою були два окремі бінарні файли компілятора, неузгоджені дані у файлі lockfile та повідомлення в Slack про те, що „7 вже є“, хоча насправді це не було так, принаймні не всюди.
Ось якою вона була на практиці: запит на зміни під назвою "видалити типизації as InvoiceId, 7 є суворішим." Насправді TypeScript 7 не був тут суворішим. У тому самому коміті також було увімкнено флаг компілятора erasableSyntaxOnly, що є зовсім окремою зміною політики та буде обговорюватися окремо пізніше. Поєднання суто продуктивного покращення зі зміною поведінкової політики — саме це і створює ці міфи.
Рішення полягає у розділенні такого коміту на дві частини: окреме підвищення версії та окрему зміну політики. Лише тоді вимірювання часу має якийсь сенс.
Речення, яке насправді опублікувала Microsoft
У офіційному оголошенні про TypeScript 7.0 від 8 липня 2026 року Даніель Розенвассер описав цю версію як ту, що забезпечує виконання коду на нативному рівні, багатопотокову обробку через спільну пам’ять, а також низку оптимізацій, які в середньому збільшують швидкість виконання у 8–12 разів під час повного збирання проекту.
Частиною цього оголошення, яку більшість людей ігнорує, є рядок про те, що система типів залишається незмінною.
Згідно з оголошенням, нова реалізація на основі Go була перенесена з існуючої через ретельний процес портування, а не створена з нуля; її поведінка у перевірці типів структурно відповідає TypeScript 6.0.
У цьому описі оновлення немає жодної нової синтаксису. Змінилась лише швидкість виконання для тієї самої основної логіки. Якщо після підвищення версії з’являються помилки типу, це не є очікуваною поведінкою — це баг, який варто задокументувати.
Next.js 16.3 додав документацію, у якій зазначено, що команда next build буде використовувати TypeScript 7 під час перевірки типів, якщо у проекті встановлений TypeScript 7 як пряма залежність. Це дає можливість вимірювати час ще в одному місці, окрім окремого запуску tsc.
Два таймери, які я насправді використовував
Протягом усіх тестів використовувалась одна й та сама тестова додаток. Next.js 16.3, React 19, чотири маршрути, таблиця рахунків-фактур; прапорець компілятора було вимкнено під час цих тестів, щоб числа не змішувалися.
Перший таймер: tsc --noEmit --extendedDiagnostics. Другий таймер: next build, з увагою до рядка про перевірку типів у його результаті.
Я додав TypeScript 7 до проекту як залежність.
pnpm add -D typescript@7
Виконуваний файл все ще називається tsc. На етапі прев’ю пакет мав назву @typescript/native-preview, а його бінарний файл — tsgo. Така номенклатура була відкинута, оскільки тепер це стабільна версія. Якщо ви натрапите на гіст чи тред, де все ще згадується tsgo, це стосується періоду прев’ю, а не поточного інструменту.
Щоб обидві основні версії могли існувати одночасно на диску, Microsoft опублікувала супутній пакет @typescript/typescript6. Він надає бінарний файл tsc6, що дозволяє звичайній команді tsc використовувати версію 7, не залишаючи команди чи інструменти, які все ще залежать від версії 6.
pnpm add -D @typescript/typescript6
Далі для обох версій використовується один і той самий файл tsconfig.json:
pnpm exec tsc6 --noEmit --extendedDiagnostics
pnpm exec tsc --noEmit --extendedDiagnostics
Ті самі вихідні файли. Та сама налаштування strict. Ті самі псевдоніми шляхів, які створив Next.js під час налаштування проекту за допомогою create-next-app.
Кожна команда виконувалася тричі, причому перший запуск відкидався, оскільки кеш файлової системи не є реалістичним показником для перевірки.
Як виглядали цифри у цьому кодбазі
У тестовому додатку є чотири маршрути та приблизно 80 файлів TypeScript, які належать до самого проекту, окрім файлів, які автоматично створює Next.js.
Виконання TypeScript 6.0 за допомогою tsc6; береться медіана двох залишених запусків:
- Кількість перевірених файлів: 412
- Час перевірки: 3,82 секунди
- Загальний час: 4,25 секунди
Виконання TypeScript 7.0 за допомогою tsc зі тією самою конфігурацією:
- Кількість перевірених файлів: 412
- Час перевірки: 0,41 секунди
Це означає приблизно у 9 разів кращий час перевірки. Не у 12 разів, і це далеко не та знижка з 125 секунд до 10 секунд, про яку іноді йдеться у сценаріях VS Code. Це просто результат роботи цього конкретного репозиторію.
Якщо подивитися на крок перевірки типів у процесі next build:
- У версії 6: 5,1 секунди
- У версії 7: 1,4 секунди
Усе інше у процесі next build — об’єднання файлів та статична генерація для чотирьох маршрутів — залишилося приблизно на тому ж рівні. Якщо ваша CI-пайплайн спочатку виконує перевірку формату, потім перевірку типів, потім збірку та нарешті тести кінцевої точки, час перевірки типів значно скоротився, але час тестів кінцевої точки не покращився.
Інший проєкт, наповнений схемами Zod та приблизно 300 файлами з логікою перевірки та обробниками, показав ще більше покращення:
- Час перевірки версії 6: 11,4 секунди
- Час перевірки версії 7: 1,3 секунди
Здається, що код із більшою кількістю типів призводить до більшого відносного покращення продуктивності. Невеликий маркетинговий сайт із десятком файлів не покаже навіть близько 10-кратного прискорення, оскільки у перевірювача майже немає матеріалу для аналізу.
Баг, який з’явився після оновлення
Це не була зміна в поведінці перевірки типів — це була проблема з інструментами.
eslint-plugin-react-hooks все ще запускав typescript через налаштування parserOptions.project. Це працювало нормально у версії 7, але зламалося під час попередніх пробних версій tsgo. Старий блок parserOptions все ще вказував на окремий файл tsconfig.eslint.json, у якому було встановлено "compilerOptions": { "strict": false } для того, щоб старі тести не скаржилися.
CI використовував ту спрощену конфігурацію для перевірки коду, тоді як tsc використовував справжню конфігурацію проекту. Два різних джерела інформації. Внаслідок цього у внутрішньому інструменті тестування залишилася прогалина з параметром noImplicitAny, яку не помічала система перевірки коду. Коли версія 7 зробила запуск tsc настільки ефективним, що його можна було запускати постійно, я додав параметр tsc --noEmit безпосередньо до перевірок у pull-request та повністю видалив спрощену конфігурацію tsconfig, призначену лише для ESLint.
{
"scripts": {
"typecheck": "tsc --noEmit",
"lint": "biome check .",
"ci": "pnpm typecheck && pnpm lint && pnpm test && pnpm build"
}
}
Справжнє рішення було не надто крутим. Існувала думка, що „версія 7 зламала наші типи“. Це не так — проблему створила дубльована конфігурація.
Перевірка того, що насправді працює на вашому комп’ютері
Перш ніж довіряти будь-яким цифрам, переконайтеся, який саме бінарний файл виконує роботу.
pnpm exec tsc -v
Ви шукаєте у результаті Version 7.x. Якщо там все ще вказано 5 або 6, ваша робоча среда використовує застарілу копію з якогось джерела. У pnpm monorepo команда which спрямує вас у неправильне місце, тоді як pnpm exec — ні.
Виконайте діагностику три рази окремо, і викиньте результат першого запуску.
pnpm exec tsc --noEmit --extendedDiagnostics
Полі, на які варто звернути увагу у цьому результаті: кількість оброблених файлів, частина загального обсягу, що походить від коду бібліотек, частина — від визначень типів, частина — це ваш власний код, а також тривалість перевірки та загальна тривалість роботи.
Тепер встановіть версію 6 поруч із версією 7 та спрямуйте їх на одну й ту саму групу файлів.
pnpm add -D @typescript/typescript6
pnpm exec tsc6 --noEmit --extendedDiagnostics
Якщо тривалість перевірки не зменшується на значну кількість у кодовій базі з сотнями файлів, це означає або що ви насправді не використовуєте версію 7, або що ваш зразок занадто малий — десяток файлів нічого не покажуть.
Також варто двічі запустити next build, по одному разу для кожного бінарника, та щоразу записувати лише інформацію про перевірку типів. Не слід об’єднувати всю тривалість збірки в один опис швидкості TypeScript — Turbopack є окремою системою, яка виконує окремі завдання.
Якщо ви зіткнулися з помилкою типу, яка з’являється у версії 7, але не у версії 6 при ідентичному tsconfig, повідомте про це. Це виходить за межі того, що обговорюється тут. Власна заява Microsoft полягає у тому, що логіка перевірки залишилася структурно незмінною, тож така різниця є багом, а не чимось, що слід вважати очікуваною вартістю міграції.
Звідки насправді походить швидкість
Приріст продуктивності полягає у самому перевірювачі. Парсинг та прив’язка також стали швидшими, але саме тривалість перевірки — це показник, який з’являється у ваших журналах CI та який люди дійсно відчувають.
Реакція редактора — це вже інша історія: це стосується мовного сервісу, а не окремого компілятора. У таблиці рахунків дії навігації, такі як переход до визначення, суб’єктивно здавалися швидшими. Час виконання кожної натиснутої клавіші не фіксувався, тому тут немає таблиці з показниками в мілісекундах.
next dev та його цикл швидкого оновлення не стали значно швидшими через цю зміну, оскільки швидке оновлення взагалі не блокувалося під час повного запуску tsc.
Справжня користь проявляється з використанням агентів чи автоматизованих циклів, які запускають tsc --noEmit після кожного обробленого файлу. Тепер цикл виконується достатньо швидко, тож оминання перевірки більше не є привабливою альтернативою. Це і є справжня, хоча й непроголошена, перевага. Той самий агент, який досі записує звичайні enum замість об’єктів as const, тепер просто швидше отримує про це інформацію.
Розрахунок фактичних витрат
Встановлення: одне оновлення залежностей та видалення залишкового скрипта tsgo, який більше не був потрібен.
Вплив на CI: у основному додатку крок перевірки типів скоротився з 3,8 секунд до 0,4 секунди; у дереві робочих процесів — з 11,4 секунд до 1,3 секунди. Решта восьми хвилин та більше процесу залишилася незмінною.
Витрати через чутки: один pull request звинувачував версію 7 у регресії, яка насправді була спричинена зміною параметра, включеною до того ж коміту. Тримайте ці коміти окремо.
Досвід роботи з редактором: приємне покращення, але не настільки значне, щоб його потрібно було квантифікувати числом у коментарях.
Найменування: tsc тепер позначає версію 7, а tsc6 — її альтернативу. Якщо обидва бінарні файли знаходяться у вашому PATH, чітко описайте це в README, щоб ніхто пізніше не заплутався.
Чи варто оновитися до версії 7 чи залишитися на 6?
Переходьте на версію 7. Функції перевірки типів залишаються такими ж, просто робота відбувається швидше — не потрібно вивчати нову синтаксис.
Залишайтеся лише на версії 6, якщо існує певний плагін, назву якого ви знаєте, і він ще не додав підтримки версії 7. Вкажіть назву цього плагіна безпосередньо у своєму значенні версії. Фраза „Чекаю, поки все стабілізується“ сама по собі не є дійсною причиною.
Не поєднуйте оновлення до версії 7 із зміною параметра erasableSyntaxOnly у одному запиті на зміни — якщо щось зламається, ви не зможете визначити, яка саме зміна цього спричинила.
Також не видаляйте команду tsc --noEmit із вашого процесу CI лише через те, що версія 7 робить його швидшим. Швидкість є причиною збереження цього етапу, а не причиною його видалення.
Чесні обмеження цього порівняння
Зниження часу виконання з 3,82 секунди до 0,41 секунди стосується саме цього додатку з чотирма маршрутами. Зниження з 11,4 секунди до 1,3 секунди спостерігалося у окремій кодовій базі, орієнтованій на виконувані скрипти. Покращення у 8–12 разів, про яке згадує Microsoft, стосується повних компіляцій у репозиторіях розміром з VS Code. Тут ніхто не перекомпілював VS Code.
Фраза „структурно ідентичні“, датована 8 липня 2026 року, походить безпосередньо з офіційного оголошення Microsoft. Якщо помилки, про які повідомляє ваш проект, дійсно змінюються після оновлення, вважайте це дефектом, який потрібно задокументувати, а не якимось дивним побічним ефектом, який можна проігнорувати.
Звідси немає можливості перевірити ваші залежності. Якщо команда pnpm exec tsc -v відображає певну версію локально, тоді як журнали CI показують іншу версію, це означає, що ви ще не перевірили TypeScript 7 насправді — у вас просто проблема з розрішенням шляху, яка маскується під порівняння версій.
Запустіть як tsc6, так і tsc по три рази кожен. Запишіть час перевірки та кількість файлів після кожного запуску. Ці чотири числа є первинним набором даних, які варто поділитися, якщо ви хочете отримати відгуки щодо вашої конкретної налаштовки.
Мінімальна схема для папки scratch
Якщо ви ще не хочете торкатися свого реального додатку, ось найменша можлива пара інсталяцій, яка все одно демонструє проблему з підняттям змін.
mkdir ts7-lab && cd ts7-lab
pnpm init
pnpm add -D typescript@7 @typescript/typescript6
echo '{ "compilerOptions": { "strict": true, "noEmit": true } }' > tsconfig.json
echo 'export type InvoiceId = string; export const n: InvoiceId = "inv_1";' > index.ts
pnpm exec tsc -v
pnpm exec tsc6 -v
pnpm exec tsc --extendedDiagnostics
pnpm exec tsc6 --extendedDiagnostics
Запишіть рядки версій та часи перевірки для обох. Потім додайте пакет робочого простору, який все ще вказує typescript@6 як залежність, та подивіться, що повідомляє команда pnpm exec tsc -v з кореня репозиторію. Саме така неузгодженість може стати несподіванкою в процесі автоматизованих тестів.
У проєкті інвойсів ще одним моментом, який варто задокументувати, є те, чи справді next build виводить рядок Finished TypeScript з версії 7. Якщо цей рядок ніколи не з’являється, це означає, що Next.js використовує окремий перевірювач типів, відмінний від того, який запускає ваш скрипт typecheck. Потрібно привести ці два інструменти у відповідність — саме через одночасне використання двох різних перевірювачів раніше пройшов баг branded-id повз перевірку.
Одноминутна перевірка для рецензентів: відкрийте app/invoices/page.tsx, наведіть курсор на тип searchParams та почекайте на підказку. Повторіть це як для версії 6, так і для версії 7. У цій перевірці не потрібен стоп-годинник — мета просто в тому, щоб переконатися, що текст підказки не змінився між версіями. Те саме поведінка, але швидший двигун під капотом.
Якщо у вашому проекті є окремий файл tsconfig.eslint.json із послабленими налаштуваннями, позбудьтеся його тієї ж тижні після оновлення. Простий перевірювач типів усуває причину для того, щоб інструмент lint перевіряв код за іншими правилами, ніж під час збірки.
Один показник, який варто фіксувати з першого дня: запустіть команду tsc --noEmit --pretty false 2>&1 та передайте результат у wc -l до та після оновлення. Кількість помилок має бути абсолютно однаковою. У додатку для рахунків-фактур це було нуль та нуль. У проекті worker-tree — чотири та чотири; у обох випадках це були ті самі файли та ті самі повідомлення. Саме ця збігність є суттю всього процесу міграції. Якщо кількості не збігаються, припиніть постійно повторювати заголовок про 10x та почніть безпосередньо порівнювати обидва логи вихідних даних.
Зберігайте обидва журнали у форматах /tmp/tsc6.txt та /tmp/tsc7.txt протягом приблизно тижня після кожного оновлення. Видаліть їх, коли ситуація стабілізується — але не в ніч, коли ви фактично розсилаєте оновлення.
Керівництво для тих, хто буде продовжувати працювати з цим кодовим базисом
У шаблоні запиту на інтеграцію необхідно вказати результат виконання команди pnpm exec tsc -v. Якщо там не вказано 7, це означає, що покращення продуктивності насправді не було впроваджене.
Не поєднуйте це оновлення з параметрами erasableSyntaxOnly, verbatimModuleSyntax чи більш масштабною очисткою tsconfig у одному зміненні. Це належить до наступних етапів роботи. Це оновлення стосується лише прискорення компілятора для виконання тієї самої роботи.
Залишайте команду tsc --noEmit у режимі роботи в CI, навіть якщо вона тепер майже не коштує зусиль. Саме ця низька вартість є аргументом на користь її збереження.
Сесія в лабораторії, записана в прямому ефірі: команди та результати
У цій частині описаний той самий лабораторний середовище для створення рахунків-фактур з чотирма маршрутами, яке використовувалося протягом усієї цієї серії. Версії, встановлені перед початком роботи: Node 24, TypeScript 7, Next 16.3.
Ці кроки знаходяться у файлі notes/lab.md репозиторію, щоб наступна сесія не залежала від пам’яті. Ви можете скопіювати їх у послідовності.
node -v
pnpm exec tsc -v
pnpm exec next --version
Запишіть усі три номери версій у верхній частині своїх нотаток. Якщо якась з основних версій не збігається з тією, яку, на вашу думку, ви використовуєте, зупиніться на цьому — все, що буде після цього, дасть оманливі результати більш тонким способом.
Далі йде огляд маршрутів:
pnpm exec next dev
Відвідайте /, /invoices, /invoices/1, /settings, а потім знову /invoices. У режимі DevTools увімкніть опцію „Зберегти журнал“. Зробіть скріншот як поля фільтрації, так і адресної строки. Ця пара даних виявляється найкориснішою для багатьох перевірок, ніж очікувалося.
Потім запустіть перевірку типів:
pnpm exec tsc --noEmit --pretty false
echo $?
Код вихіду 0 — це не кінцевий результат; це лише сигнал до перевірки поведінки програми під час виконання.
Нарешті, те, про що справді йдеться в усьому цьому тексті: виконайте команди, які вже наведені під розділом «Як переглянути це на вашому пристрої». Не пропускайте їх лише тому, що ви вже бачили тут числа — ваш пристрій не є тим, звідки вони походять. Навколишня температура, ноутбук на 16 ГБ та будь-які процеси, які Chrome виконує на фоні, значно більше вплинуть на показники RSS, час перевірки та час припинення завантаження, ніж будь-яке незначне оновлення фреймворку.
Ще одна звичка, яку варто зберегти: один рядок у примітках про «невдалий спробу виправлення» — одне речення, щось на кшталт «Спробував X, але все одно бачу Y». Саме цей рядок допомагає зберегти запис у форматі функціонального звіту, а не відформатованої презентації. Корисним доповненням є список версій, точна команда, результат виконання та опис невдалих спроб виправлення. Скріншот панелі керування — ні.
Пов’язана література
- Компілятор TypeScript на Go та нативна екзекуція: посібник з міграції — Дізнайтеся, як компілятор TypeScript на основі Go та нативна екзекуція в Node.js вплинуть на кодові бази React та Next.js, і що потрібно виправити у вашому tsconfig прямо зараз.
- Як працює переписування коду TypeScript 7 на Go: прискорення без змін у коді — Дізнайтеся, як компілятор TypeScript 7 на основі Go забезпечує у 8–12 разів швидшу компіляцію, чому така зміна архітектури ефективна та як безпечно оновити існуючі проекти.