Главная / Статьи / 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 с сотнями компонентов больше не рассматривают проверку типов как узкое место в процессе интеграционного тестирования, каким она была раньше. Проекты, построенные с использованием сложных генерических типов, таких как те, что сочетают 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 раз более быструю сборку, почему такой изменение архитектуры эффективно и как безопасно обновить существующие проекты.