Головна / Статті / TypeScript 7.0 переходить на компілятор Go для досягнення максимальної швидкості

TypeScript 7.0 переходить на компілятор Go для досягнення максимальної швидкості

TypeScript 7.0 переносить tsc у середовище Go із паралельними перевірниками, новими значеннями за замовчуванням для tsconfig, шаблонними літералами Unicode, суворішою аналізом JS та тимчасовою відсутністю програмної API.

1086 слів

Протягом приблизно чотирнадцяти років компілятор TypeScript міг самостійно собою створюватися. tsc був версією TypeScript, яка компілювалася у JavaScript та працювала на Node. Коли кількість коду досягла мільйонів рядків, така самостійна архітектура стала перешкодою.

У TypeScript 7.0 змінилася мова, на якій працює компілятор. Компілятор та сервіс мови перейшли з TypeScript на Go. Microsoft описує ці зміни як порт, а не повну переробку: структура перевірки типів залишилася такою ж, як у версії 6.0, але виконання відбувається за допомогою нативного коду з паралелізмом через спільну пам’ять. У опублікованих порівняннях часто фіксується прискорення приблизно у 10× порівняно з TypeScript 6.0.

Один із часто наводжених прикладів демонструє конкретну користь від цих змін. Перевірка коду у VS Code — що складається приблизно з 1,5 мільйона рядків TypeScript — скоротилася з приблизно 77,8 секунд до близько 7,5 секунд.

Якщо ранні версії використовували кодову назву Project Corsa (а стара версія JavaScript мала прізвисько Strada), то ця версія є результатом цих зусиль.

Чому саме Go та чому порт?

У громадських припущеннях часто згадувався Rust. Було обрано Go тому, що він узгоджується з існуючою структурою компілятора: складні графи, збір сміття та циклічні структури, які складно створити з нуля. Саме ця узгодженість уможливила портинг рядок за рядком.

Формат порту має більше значення, ніж сама мова. Збереження архітектури дозволило зберегти правила. Проекти, які вже проходять перевірку типів під версією 6.0 із увімкненим stableTypeOrdering та без ignoreDeprecations, мають отримувати такі самі результати під версією 7.0 — просто швидший двигун, а не інша система типів.

Спочатку проводилися тести на навантаження під час обробки даних. Протягом понад року цей порт працював на величезних серверах у таких компаніях, як Bloomberg, Figma, Google, Slack, Notion та Vercel, перш ніж було досягнуто цього етапу.

Справжній паралелізм

Раніше пропускна здатність обмежувалася одним потоком Node. Нативні працівники усувають це обмеження. У версії 7 робота з аналізу, перевірки та виведення даних розподіляється, а також додаються прапорці:

  • --checkers встановлює кількість паралельних працівників для перевірки типів
  • --builders здійснює паралелізацію процесу створення проектів та стеків разом із --checkers у монорепозиторіях
  • --singleThreaded об’єднує всю роботу в один ядро для дебаггінгу та вимірювання базових часів виконання

Обсяг роботи з аналізу/виведення даних за кожним файлом зростає разом із розміром та модульністю репозиторію; дуже маленькі однокористувацькі додатки отримують меншу користь від цього.

Режим спостереження також було оновлено. Метод опитування споживав велику кількість ресурсів CPU у великих деревах node_modules; використання механізму спостереження Parcel у Go знижує цей ресурсне навантаження та дозволяє швидше реагувати на зміни.

Зміни конфігурації, які створять труднощі для команд

TypeScript 6.0 виступив посередником: нові значення за замовчуванням та скасувані функції з’являлися як попередження. У версії 7.0 вони стають серйозними помилками. Команди, які вже пройшли версію 6.0, виконали більшу частину роботи. Перехід від версії 5.x безпосередньо до 7.0 вимагає часу на очищення файлу tsconfig.json.

Основні зміни за замовчуванням:

  • strict увімкнено, якщо не було вказано інше
  • module встановлюється на esnext, тоді як target обирає найновішу стабільну версію ECMAScript, яка є меншою за esnext
  • noUncheckedSideEffectImports увімкнено за замовчуванням
  • libReplacement вимкнено за замовчуванням
  • stableTypeOrdering залишається увімкненим
  • rootDir починається з ./
  • types спочатку є порожнім списком
  • У документації зазначається, що rootDir та types — це перші проблеми, з якими стикаються команди, і саме їх можна вирішити найпростіше.

    Якщо файл tsconfig.json знаходиться над папкою src, явно встановіть rootDir, щоб форматування залишалося знайомим:

    {
      "compilerOptions": {
        "rootDir": "./src"
      },
      "include": ["./src"]
    }
    

    Оскільки types більше не автоматично імпортує все з node_modules/@types, вкажіть те, що вам потрібно:

    {
      "compilerOptions": {
        "types": ["node", "jest"]
      }
    }
    

    Опції, які раніше лише попереджали, тепер призводять до серйозних проблем (вони перестають виконувати будь-яку корисну функцію):

    • Видаліть target: es5 та downlevelIteration
    • Замініть застарілі значення moduleResolution (node, node10, classic) на nodenext або bundler
    • Відмовтеся від режимів module, таких як amd, umd, systemjs та none, на користь esnext або preserve
    • Видаліть baseUrl та вказуйте paths відносно кореня проекту
    • Не ставте esModuleInterop / allowSyntheticDefaultImports на значення false
    • Вважайте, що параметр alwaysStrict постійно увімкнений

    Якщо через багато років без перевірки значення moduleResolution досі залишається старим node, цей файл є чек-листом для міграції.

    Unicode у типах з літеральними шаблонами

    Типи літеральних шаблонів тепер ґрунтуються на код-пунктах Unicode, а не на одиницях коду UTF-16:

    type HeadTail<S> = S extends `${infer Head}${infer Tail}` ? [Head, Tail] : never;
    
    type Result = HeadTail<"😀abc">;
    // In 7.0:      ["😀", "abc"]
    // Previously:  ["\ud83d", "\ude00abc"]
    

    Старіші компілятори могли розбивати пару замінників емодзі. Це відповідало способу індексації в JS та рідко відповідало намірам автора. Тепер ітерація відбувається за код-пунктами, як це роблять for...of та [...str]. Інструменти, які навмисно підраховували одиниці UTF-16, будуть не працювати; у всіх інших буде саме та поведінка, якої вони очікували.

    Суворіший аналіз JavaScript

    Перевірка файлів .js раніше толерувала більше ідіом з епохи JSDoc та Closure. Версія 7 ще більше наближає цей підхід до правил .ts:

    • Місця, де потрібні типи, відхиляють прості значення — краще використовувати typeof someValue
    • @enum / @class втрачають спеціальне оброблення; потрібно оголосити справжній клас або використати @typedef
    • Просте ? не приймається як тип — краще використовувати any
  • Післякоментарні оператори перевірки ! не підтримуються — необхідно явно вказувати T
  • Старі формати function(string): void поступаються місцем (s: string) => void
  • Прогалина в програмному API

    У версії 7.0 все ще відсутнє стабільне програмне API. Тому бібліотеки, які вбудовують компілятор — інтеграція TypeScript у ESLint, ts-morph, власноруч створені трансформатори, а також інструменти для редагування шаблонів Vue, Svelte, Astro, MDX чи Angular — ще не можуть повністю перейти на нову систему. Microsoft вважає цю прогалину тимчасовою та очікує завершення розробки API у версіях 7.1 та новіших.

    Тим часом використовуйте версію 7.0 там, де не потрібні плагіни language-server. Команди Angular, наприклад, можуть запускати tsc з версії 7.0 для швидких перевірок усього проекту за допомогою CLI, зберігаючи при цьому версію 6.0 у редакторі. Пакет сумісності @typescript/typescript6 надає бінарник tsc6 та знову експортує API версії 6.0, щоб обидві версії могли існувати разом:

    {
      "devDependencies": {
        "typescript": "npm:@typescript/typescript6@^6.0.0"
      }
    }
    

    Чи варто оновлюватися?

    Якщо ви вже використовуєте TypeScript 6.0, міграція є простою, а користь значною: достатньо змінити кілька параметрів tsconfig, щоб отримати швидші перевірки CI та швидше завантаження редактора. Для старіших версій існують справжні проблеми з сумісністю, але майже всі вони вже були попереджені.

    Встановіть кандидата на випуск ще сьогодні:

    npm install -D typescript@rc
    

    Щодо редакторів, сьогодні додаток для VS Code підтримує протокол LSP, а нативна інтеграція з VS Code постійно розвивається. Visual Studio виявляє версію 7.0 у відкритому робочому просторі без необхідності окремої процедури встановлення.

    Розробники кажуть, що випуски з новими функціями знову будуть відбуватися за звичним багатомісячним ритмом, і очікується, що версія 7.1 заповнить прогалину в API для вбудовування.

    Кінцевий результат: знайомі правила TypeScript, які працюють як нативний код.