Головна / Статті / TypeScript 6 та 7: розумніше інференсування, потім перепис на основі Go

TypeScript 6 та 7: розумніше інференсування, потім перепис на основі Go

Дізнайтеся, як TypeScript 6 усунув проблеми з автоматичним визначенням ключів та оновив стандартні параметри, створивши основу для повної переробки компілятора в TypeScript 7 на мові Go.

1255 слів

Останнім часом TypeScript вдосконалюється у двох окремих напрямках, і разом вони розповідають одну історію: мова стає як розумнішою, так і швидшою. TypeScript 6, який був випущений як остаточна версія, написана за допомогою традиційного компілятора на основі JavaScript перед великою архітектурною зміною, був спрямований на усунення давніх проблем із інференцією та модернізацію стандартних налаштувань. TypeScript 7 зробив ще більш радикальний крок, переписавши сам компілятор на мові Go, прагнучи до максимальної швидкості, а не до нової синтаксису. Якщо розглядати обидва кроки разом, можна побачити, як інструментарій досяг свого поточного стану — спочатку ставши більш точним, а потім значно швидшим.

Розумніша інференція в TypeScript 6

Кожен, хто коли-небудь вводив скорочену версію методу, а потім бачив, як параметр поступово перетворюється на any, розуміє, наскільки дратівливими можуть бути старі правила інференції TypeScript. TypeScript 6 вирішує цю проблему, а також кілька інших прогалин у механізмі інференції, які роками змушували розробників шукати відповіді.

Раніше будь-яка функція, яка внутрішньо посилалася на this, вважалася „чутливою до контексту“, що означало, що компілятор повністю ігнорував інференцію типу параметра — навіть у випадках, коли this насправді ніколи не використовувався всередині тіла функції:

// Old behavior: 'user' silently became 'any'
const handlers = {
  onSave(user) {
    console.log(user.name); // no autocomplete, no error
  },
};

У TypeScript 6 компілятор вважає функцію контекстно чутливою лише тоді, коли всередині неї дійсно використовується this. Якщо цього не відбувається, активується звичайний механізм інференції, і параметр отримує свій очікуваний тип замість того, щоб переходити на any:

// TypeScript 6: 'user' is correctly inferred from context
const handlers: Handlers = {
  onSave(user) {
    console.log(user.name); // fully typed
  },
};

Це здається незначною технічною корекцією, але вона має значний вплив на щоденну розробку, особливо у кодових базах React та Next.js, де методи об’єктів та обробники подій є скрізь. TypeScript 6 також забезпечує першокласну підтримку декларацій using, які формалізують пряме керування ресурсами. Замість того, щоб вручну обгортати логіку очищення у блок try/finally, можна дозволити компілятору автоматично керувати її виконанням після того, як значення виходить за межі своєго діапазону:

function readConfig() {
  using file = openFile("./config.json"); // auto-disposed at scope end
  return JSON.parse(file.read());
}

Імпорти підшляхів також стають більш чистими. Префікс #/ тепер функціонує через поле imports, що дозволяє уникати довгих ланцюгів відносних шляхів ../../../:

{
  "imports": {
    "#/*": "./src/*"
  }
}
import { formatCurrency } from "#/utils/currency";
// instead of: import { formatCurrency } from "../../../utils/currency";

Кілька значень за замовчуванням також змінилися. Параметр target тепер за замовчуванням встановлюється на ES2023 замість старої версії ES3, параметр module — на ESNext, а параметр moduleResolution — на bundler. Параметр types також за замовчуванням має значення порожнього масиву, що запобігає автоматичному скануванню та завантаженню всіх пакетів @types, які може знайти TypeScript. За даними Microsoft, саме ця зміна сприяла покращенню швидкості компіляції на 20–50 відсотків, тож перегляд вашого файлу tsconfig.json є доцільним навіть у разі відсутності бажання використовувати нові функції мови.

У сукупності рекомендації TypeScript 6 полягають у наступному: перевірте всі об’єкти з великою кількістю методів у вашому кодбазі, адже вони можуть отримати автоматичні покращення щодо безпеки типів без додаткових зусиль; використовуйте ключове слово using там, де ви працюєте з файлами, підключеннями чи таймерами, які потребують очищення; не просто мовчки успадковуйте нові стандартні налаштування компілятора — встановіть їх явно у файлі tsconfig.json, щоб ваша мета була зрозумілою; а також очікуйте, що типові визначення, які надають фреймворки та бібліотеки на кшталт React, Redux та інструментарію Tailwind, пристосуються до цих змін протягом наступних тижнів. TypeScript 6 — це не тимчасова версія; він значно зменшує кількість несподіванок, пов’язаних із інференцією типів, з якими ви стикаєтесь щодня, і це саме по собі є достатньою причиною для оновлення.

Повне переписування в TypeScript 7

Якщо TypeScript 6 вдосконалив спосіб, яким компілятор аналізує типи, то TypeScript 7 націлений на щось більш фундаментальне — швидкість роботи всього інструментарію. Microsoft повністю переписав компілятор, сервіс мови та супутні інструменти на Go, замінивши самостійно реалізовану версію на JavaScript, яка працювала з TypeScript протягом багатьох років. Це не просто незначне оновлення версії — його описують як найбільшу зміну продуктивності в історії мови.

Кожен, хто коли-небудь дивився на індикатор завантаження в редакторі, чекаючи на появу помилки типу, зрозуміє, на яку проблему спрямовано це оновлення.

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

Опубліковані самою Microsoft тестові дослідження дають уявлення про масштаб покращень. У кодовій базі VS Code, яка налічує приблизно 1,5 мільйона рядків, повна компіляція, яка раніше тривала близько 125 секунд, тепер завершується приблизно за 10 секунд. Час виявлення першої помилки типу в редакторі зменшився з приблизно 17 секунд до менше ніж 1,5 секунди. Використання пам’яті знизилося приблизно на 18 відсотків, а крахи мовного сервера — на понад 60 відсотків. Це також не суто синтетичні цифри — компанії, зокрема Slack, Figma, Google, Notion та Vercel, протестували новий компілятор у реальних проектах ще до його випуску та повідомили, що покращення зберігалися навіть поза межами контрольованих тестів.

Для команд, які працюють з React та Next.js, це призводить до конкретних щоденних переваг. У великому монорепозиторії раніше очікування на те, поки tsc виявить неузгоджені типи, могло тривати кілька секунд; цей час обробки значно скорочується завдяки компілятору на основі Go:

// Before: waiting on tsc to catch this in a large monorepo could take seconds
interface UserCardProps {
  name: string;
  avatarUrl?: string;
  onSelect: (userId: string) => void;
}

function UserCard({ name, avatarUrl, onSelect }: UserCardProps) {
  // With TS7's native checker, this feedback loop is nearly instant
  return (
    <button onClick={() => onSelect(name)} className="rounded-lg p-2 hover:bg-slate-100">
      {avatarUrl && <img src={avatarUrl} alt={name} className="h-8 w-8 rounded-full" />}
      <span>{name}</span>
    </button>
  );
}

Великі додатки Next.js із сотнями компонентів більше не розглядають перевірку типів як вузьке місце у процесі CI, як це було раніше. Проекти, побудовані з використанням складних генеричних типів, таких як ті, що поєднують Tailwind та Redux, мають значно швидшу інкрементальну збірку. Автодоповнення в редакторі у великих монорепозиторіях також працює набагато швидше.

Перед оновленням є кілька моментів, на які варто звернути увагу. Тепер строгий режим є значенням за замовчуванням, тож раніше менш суворі кодові бази можуть виявити нові помилки. Класичні цілі компіляції, такі як es5, разом із старішими налаштуваннями розрішення модулів, більше не є просто попередженнями — вони розглядаються як серйозні помилки. Крім того, оскільки програмний API в цьому випуску є лише частково стабільним, будь-які фреймворки чи інструменти, які залежать від нього безпосередньо, повинні почекати до версії TypeScript 7.1 перед оновленням.

У всьому цьому немає нічого нового щодо синтаксису чи принципово іншої граматики — TypeScript 7 існує переважно для вирішення проблеми з продуктивністю компілятора, яка існує вже десятиліття. Якщо ваша команда працює з великою базою коду на React чи Next.js, це саме та версія, яка нарешті робить tsc менш проблематичним у використанні. Як і при будь-яких значних змінах в інфраструктурі, варто спочатку спробувати їх у побічній гілці; ваша CI-пайплайн подякує вам за обережність.

Пов’язана література

  • Роль мосту TypeScript 6 на шляху до нативного компілятора TS 7 — Дізнайтеся, як TypeScript 6 оновлює стандартні налаштування, механізми розрішення модулів та синтаксис імпорту, щоб підготувати кодові бази до швидшого компілятора TypeScript 7, заснованого на Go.
  • Як працює переписування на Go у TypeScript 7: прискорення без змін у коді — Дізнайтеся, як компілятор TypeScript 7, заснований на Go, забезпечує у 8–12 разів швидшу компіляцію, чому така зміна архітектури ефективна та як безпечно оновити існуючі проекти.