В середине марта 2023 года Майкрософт анонсировала релиз TypeScript версии 5.0. Разработчики ожидают от нее 10-20% прироста производительности, но так как всё зависит от кодовой базы и характеристик оборудования, они настоятельно рекомендуют опробовать эти изменения. В этой статье мы разберём некоторые изменения в TypeScript 4.9 и 5.0 и сравним нововведения с предыдущими версиями. На примерах кода постараемся понять, для чего они были добавлены и как они упрощают нашу жизнь. Статья будет полезна опытным разработчикам, которые часто применяют TypeScript в работе, и начинающим, так как мы подробно разберем решения некоторых проблем. Позволяет нам проверить соответствие выражения некоторому типу, не меняя сам тип. Это помогает при работе с объектами со смешанными типами данных. Рассмотрим на примере: Объект data имеет как числовые, так и строковые значения, поэтому при работе с этим объектом мы получаем следующие ошибки: Вот тут-то нам и поможет оператор satisfies. Также оператор satisfies можно использовать для отлова некоторых ошибок. Например, для проверки объектов на наличие ключей, соответствующих заданному типу: Оператор in в JavaScript — помогает понять нам, существует ли свойство у объекта. В TypeScript он помогает отделить один тип от другого. Но с этим оператором возникала следующая ошибка: Предположим, что есть объект, который приходит с сервера. При работе с ним мы проверяем наличие свойства, которое нас интересует, и если это свойство существует, то выполняем инструкции, находящиеся в блоке if. В старых версиях TypeScript приводит response к типу object, и показывает такую ошибку: Хотя выше проверка на наличие этого свойства прошла успешно. Мы можем конвертировать переменную response, допустим, к типу any:  Но делать это не рекомендуется, так как это может негативно отразиться на безопасности проекта. К нам на выручку приходит TypeScript версии 4.9. При проверке наличия свойства через оператор in, правому операнду TypeScript сужает тип до: Благодаря этой возможности мы можем использовать эту конструкцию без конвертации объекта response. В TypeScript 4.9 появилась поддержка новой функции auto-accessor из ECMAScript. Ключевое слово accessor — это синтаксический сахар для создания get и set методов приватного свойства. До появления accessor поля класса с помощью декораторов пытались превратить в свойства путём добавления get/set методов. Auto-accessor решает эту проблему. Auto-accessor имеет несколько возможностей: Позволяет подклассам переопределять get/set без поля суперкласса. При применении декоратора к такому свойству, он получает доступ к get/set методам и может дополнять их без изменения структуры класса. Пример нового декоратора из TypeScript 5.0 для accessor поля: Пример без accessor: Пример с accessor: NaN — специальное числовое значение, расшифровывается как «Not A Number». Результатом сравнения числового значения или же самого NaN с NaN будет false. Лучшее решение проверить, является ли значение NaN — использовать статический метод isNaN класса Number. В предыдущих версиях TypeScript не обращал внимание на прямое сравнение с NaN. В версии 4.9 при прямом сравнении значения с NaN TypeScript выбрасывает ошибку: В предыдущих версиях TypeScript существовала команда «Organize Imports», которая удаляла неиспользуемые импорты, и переписывала файл, сортируя оставшиеся импорты. В TypeScript 4.3 добавили команду только для сортировки импортов «Sort Imports». Её проблема заключалась в том, что она была доступна как команда при сохранении, и не запускалась вручную. В версии 4.9 появилась команда «Remove unused imports», которая удаляет неиспользуемые импорты, не меняя их порядок. Теперь все три команды доступны во всех редакторах кода. TypeScript версии 4.9 имеет несколько небольших, но заметных улучшений производительности. Вот две функции, на которых эти изменения отразились больше всего: forEachChild — является основной функцией для обхода синтаксических узлов в компиляторе. Благодаря рефакторингу этой функции удалось ускорить этап связывания (binding) на 20%. Вслед за успехом оптимизации функции forEachChild эти же приёмы опробовали на функции visitEachChild — она используется для преобразования узлов компилятора. Прирост производительности составил 3%. Это обыкновенные функции, которые позволяют добавить дополнительное поведение классу, методу, свойству. Пример класса без декоратора:  Мы видим, что нам необходимо добавить логирование для метода, чтобы отследить его работу. В этом случае к нам на помощь приходят декораторы. Пример декоратора: Декоратор принимает функцию, к которой мы применяем этот декоратор и контекст.И возвращает функцию, в которой мы можем добавить логирование, главное, не забыть вернуть результат выполнения функции target. Теперь посмотрим, как применить декоратор к нашему классу:  Функции-декораторы можно объединять в цепочки. Например, представим, что нам необходимо добавить валидацию для метода changeAge. Делать проверку непосредственно внутри метода не будет являться хорошим тоном, так как если нам понадобится добавить такую же валидацию в другой метод, мы будем нарушать принцип DRY. Правильным решением в данном случае будет воспользоваться декоратором.Обернём декоратор в функцию высшего порядка для передачи параметра, в нашем случае, минимального значения извне. Теперь воспользуемся этим декоратором:  Мы смогли добавить валидацию на метод changeAge, при этом сохранили логирование этого метода. Декораторы можно использовать не только для методов класса, «декорировать» можно также свойства класса, геттеры и сеттеры, auto-accessor, а также и сами классы. В TypeScript 5.0 добавлена возможность работать с типом, который передаём в дженерик, как с литералом. Рассмотрим на примере: Создадим функцию, в которую будем передавать массив пользователей. Функция возвращает другую функцию, при вызове которой мы получим пользователя, чьё имя мы в неё передали. И переменная currentUser будет равна undefined, так как мы передали имя пользователя, которого нет в массиве users. Чтобы избежать этой проблемы, в TypeScript 5.0 добавили возможность использовать const нотацию в generic. Чтобы её использовать, достаточно добавить const в generic функции parseUsers. Теперь при вызове функции getUsers с именем пользователя, которого нет в массиве users, TypeScript выдаст нам ошибку: В TypeScript 5.0 изменилось поведение работы перечислений. При создании перечисления каждому его ключу присваивается числовое значение, соответствующее его порядковому номеру, начиная с 0. Напишем функцию, которая будет принимать значения перечисления, и сообщение. При работе с этой функцией первым параметром мы можем передать числовое значение, соответствующее значению перечисления. В предыдущих версиях TypeScript мы могли передать любое числовое значение: В TypeScript 5.0 этот кейс исправили, теперь при передаче значения которого нет в перечислении, появляется ошибка: Конечно, передавать значения перечисления таким образом является плохим тоном. Гораздо правильнее делать это так: В любом случае очень хорошо, что подобные ошибки не забываются и исправляются. Также в TypeScript 5.0 все перечисления теперь рассматриваются как объединённые перечисления, удалось этого достичь путём создания уникального типа для каждого вычисляемого значения перечисления.Рассмотрим на примере версии до 5.0: Получим ошибку:    В TypeScript 5.0 всё работает без ошибок. В TypeScript существует возможность подключать сторонний конфигурационный файл, указав путь до него в поле extends: Раньше можно было указать путь только для одного файла. В версии 5.0 для большей гибкости в настройке TypeScript добавили возможность указывать путь до нескольких файлов: TypeScript версии 5.0 добавляет множество изменений в структуре кода, структуре данных и алгоритмических реализациях. Это позволяет ускорить не только работу TypeScript, но даже и его установку. Вот некоторые улучшения в скорости и размере, их удалось достичь в сравнении с TypeScript 4.9: Одним из главных изменений стал перевод TypeScript с пространства имён на модули, это позволяет использовать современные инструменты сборки. Применение этого инструментария, удаление неиспользуемого кода, пересмотр стратегии сборки позволили сократить размер бандла на 26,5 МБ от общего размера в 63,8 МБ, и также заметно ускорить работу TypeScript. Резюмирую изменения, которые произошли с TypeScript в версии 4.9 и 5.0. Мне показалось, что изменений в TypeScript 4.9 было немного, но они значимы:  новый оператор — satisfies улучшения при сужении типов в операторе in Версия 5.0, наоборот, очень богата на изменения и добавления новых, удобных возможностей:  функции — декораторы возможность подключить несколько конфигурационных файлов  улучшения в работе с enum множество изменений в оптимизации работы TypeScript Эти версии не похожи друг на друга, но объединяет их то, что они делают нашу жизнь чуточку лучше, а работу — немного приятнее.  Спасибо за внимание! Авторские материалы для frontend-разработчиков мы также публикуем в наших соцсетях – ВКонтакте и Telegram.