Что нового в TypeScript 4.6?
TypeScript 4.6 — это первый в этом году выпуск функций надмножества статически типизированного JavaScript. Он добавляет несколько улучшений, касающихся конструкторов, компиляции и анализа кода. Есть также несколько критических изменений, о которых следует знать перед обновлением.
Усовершенствования анализа потока управления
В этом выпуске реализовано несколько улучшений возможностей анализа потока управления TypeScript. Они лучше оснащены TypeScript для более точного понимания того, как работает ваш код, что приводит к более узким определениям типов и меньшему количеству непредвиденных ошибок.
Первое изменение касается дискриминантных объединений свойств, которые были деструктурированы из объектов. Это применимо к случаям, когда вы работаете с типами объединения, состоящими из нескольких объектов. Отдельные объекты в объединении могут иметь разные определения типов, но по-прежнему иметь общие ключи.
Обычно эти общие ключи используются для условной проверки других частей структуры данных. TypeScript раньше приводил к ошибкам при использовании этого рабочего процесса с назначением деструктурирования. Синтаксис деструктурирования создал совершенно новые переменные, лишенные ассоциации, которая связывала их как свойства объекта. Теперь компилятор запоминает, что значения были получены из одного и того же объекта, что позволяет писать более простой код.
В объявлении о выпуске используется пример, похожий на этот:
type Action = | {kind: "Number", data: number} | {kind: "String", data: string}; function handle(action: Action) { const {kind, data} = action; if (kind === "Number") { const square = (data * data); } else if (kind === "String") { const lines = data.split("n"); } }
TypeScript 4.5 не разрешил бы этот код. Назначение деструктурирования (const {kind, data}
) создало две независимые переменные; компилятор не мог понять, что kind
, будучи Number
, означает, что data
должен быть типом number
. Теперь он распознает этот факт, позволяя вам использовать синтаксис деструктуризации с размеченными объединениями.
Анализ потока управления также был усилен вокруг зависимых параметров. Этот синтаксис позволяет задавать сложные правила для природы вариативных параметров. Вот определение типа функции, использующей это поведение:
type Func = (...args: ["Number", number], ["String", string]) => void;
Сигнатура этой функции указывает, что вы можете передать либо String
, либо Number
в качестве ее первого параметра. Если вы используете Number
, следующим параметром должно быть значение типа number
. В качестве альтернативы можно указать string
, если он следует за String
.
Как и в приведенном выше примере с размеченными объединениями, TypeScript теперь сужает тип зависимых параметров на основе значений, которые им предшествовали:
const demo: Func = (kind, data) => { if (kind === "Number") { const square = (data * data); } else if (kind === "String") { const lines = data.split("n"); } };
Теперь компилятор понимает, что data
должен быть числом
, если kind
равен Number
. Этот код выдал бы ошибку с TypeScript 4.5.
Усовершенствования конструктора
Конструкторы классов JavaScript, которые расширяют родителя, должны вызывать super()
, прежде чем можно будет использовать ключевое слово this
:
// Not allowed - "this" used before "super" class B extends A { constructor() { this.demo = "foobar"; super(); } } // Working correct order class C extends A { constructor() { super(); this.demo = "foobar"; } }
Исторически TypeScript слишком строго соблюдал это требование. Классы, содержащие инициализаторы свойств, будут отклонены, если перед оператором super()
у них будет какой-либо код, даже если он никогда не ссылался на this
:
const example = () => null; class C extends A { demoProperty = true; // Unnecessarily treated as invalid constructor() { example(); super(); } }
Эта обработка помогла оптимизировать проверки TypeScript на наличие подлинных экземпляров this
, используемых перед super()
. Это также привело к тому, что большое количество приемлемого кода не смогло скомпилироваться, что вынудило авторов провести рефакторинг работы, которая на самом деле была действительным JavaScript.
TypeScript 4.6 решает эту проблему. Теперь компилятор соответствует ванильному JavaScript, разрешая код перед super()
, если это не приведет к использованию this
. Это дает вам больше свободы для написания конструкторов классов наиболее подходящим для каждой ситуации способом. TypeScript по-прежнему будет обнаруживать любые реальные случаи ссылки на this
слишком рано.
Дополнительные улучшения логического вывода
Выводы индексированного доступа теперь более точны. Это дает компилятору видимость индексированных типов доступа, которые индексируют сопоставленные объекты. Хотя это уже было возможно раньше, старые выпуски TypeScript давали вывод низкого качества, который не всегда полностью осознавал типы отображаемых объектов.
Проверки глубины рекурсии TypeScript также были скорректированы, чтобы обеспечить лучшее обнаружение несовместимых рекурсивных типов. Это изменение может улучшить производительность проверки типов, поскольку оно облегчает более раннее аварийное завершение работы, когда рекурсия типа начинает бесконечно расширяться. Улучшения сосредоточены на том, как рекурсия применяется к типам, использующим универсальные шаблоны.
Таргетинг ES2022
Флаг --target
получил поддержку es2022
в качестве значения. Он позволяет в полной мере использовать функции ES2022, обеспечивая сохранение синтаксиса, такого как поля класса и свойство Error.cause
, без транспиляции в ваших стабильных сборках.
Вы можете настроить таргетинг на ES2022, передав флаг --target es2022
в tsc
. Либо измените compilerOptions.target
на es2022
в файле tsconfig.json
вашего проекта:
{ "compilerOptions": { "target": "es2022" } }
Другие ошибки синтаксиса и привязки JavaScript
TypeScript теперь отображает больше стандартного синтаксиса JavaScript и ошибок привязки. Эти ошибки будут отображаться во время компиляции и при открытии файлов в редакторе с установленным расширением TypeScript для Visual Studio, Visual Studio Code или Sublime Text.
Повторяющиеся операторы const
, неправильное использование ключевых слов и ошибки области действия теперь будут обнаруживаться TypeScript, предоставляя вам немедленную обратную связь во время работы. Функцию можно отключить, добавив комментарий // @ts-nocheck
вверху ваших исходных файлов.
Это дополнение представляет собой критическое изменение, поскольку исходные файлы теперь должны содержать грамматически правильный JavaScript. Ранее компилятор TypeScript игнорировал большинство синтаксических ошибок JavaScript. Вы должны использовать комментарий, чтобы отключить эту функцию, если вы считаете, что ваша кодовая база будет несовместима с этим принудительным исполнением.
Еще одно критическое изменение
В этом обновлении есть второе критическое изменение: выражения остатка объекта теперь удаляют нерасширяемые члены из универсальных объектов. Это улучшает согласованность при деструктурировании необобщенных типов, но означает, что ваши существующие переменные могут не иметь некоторых свойств, которыми они обладали в TypeScript 4.5.
Свойства с нерасширяемыми значениями, такие как скаляры и функции, будут исключены из остальных выражений. Это также относится к другим нерасширяемым случаям, таким как непубличные члены экземпляров класса и this
. Такой код раньше работал, но теперь выдает ошибку:
class Demo { prop = "example"; sayHello() { console.log("Hello World"); } methodWithRest() { const {prop, ...rest} = this; // ERROR - Non-spreadable value (function) will be dropped rest.sayHello(); } }
Краткое содержание
TypeScript 4.6 улучшает вывод типов, улучшает обработку конструктора дочернего класса и добавляет ES2022 в качестве поддерживаемой цели вывода. Есть также несколько узких критических изменений в виде расширенного обнаружения синтаксических ошибок JavaScript и удаления нерасширяемых членов выражения остатка объекта. Вы можете выполнить обновление до новой версии, запустив npm update typescript
или npm install typescript@latest
в рабочем каталоге вашего проекта.
Обновление также знаменует собой дебют нового расширенного инструмента для анализа существующих трассировок генерации типов TypeScript. Анализатор трассировки работает с выходными данными tsc --generateTrace
, чтобы помочь вам определить, насколько сложные выражения типа замедляют работу компилятора.