Вышел TypeScript 5.6.
Релиз задержался на шесть дней, но это того стоило. Рассказываю, чего мы дождались.
Новые методы итераторов.
Мелочь, но как же я давно об этом мечтал. Теперь у итераторов есть методы map, filter и reduce — прям как у массивов. Но в отличие от массивов, они позволяют работать с коллекциями лениво. Вот мой любимый фокус:
const numbers = [1, 2, 3];
const squares = Iterator
.from(numbers)
.map((x) => x ** 2);
numbers.push(4);
console.log(squares.toArray()); // => [1, 4, 9, 16] Метод Iterator.from — это ещё один новый метод. Он конвертирует переданный объект в объект итератора.
Мне нравится, что теперь можно оптимизировать цепочки вызовов map и filter. Например, вот одна из функций, которая используется при сборке этого сайта:
function getInnerText(target: HTMLElement): string {
return Iterator.from(target.childNodes)
.filter((node) => !(isHTMLElement(node) && node.classList.contains("code-listing-comment")))
.map((node) => node.textContent)
.toArray()
.join("");
} Методы filter и map не создают промежуточные массивы (как в случае с методами типа Array). Это может здорово сэкономить память, если у тебя куча элементов в массиве. Хотя странно, что не добавили метод join, как у массивов.
Ну и, конечно, ленивость прекрасна тем, что позволяет работать с бесконечными структурами данных. Бесконечные массивы в работе никогда не приходилось использовать, но сама идея мне безумно нравится 🙃.
function* countFrom(start: number): Generator<number> {
for (let i = start; ; i++) {
yield i;
}
}
const firstFiveSquares = countFrom(0)
.map(x => x ** 2)
.take(5)
.toArray();
console.log(firstFiveSquares); // => [0, 1, 4, 9, 16] Ошибиться в условиях теперь сложнее.
Такой код больше не скомпилируется:
// Компилятор выводит ошибку:
//
// This kind of expression is always truthy.
//
if (2) {
console.log("2 is truthy");
} if всегда истинно. Некоторые компиляторы могут убирать такие лишние проверки и оставлять только тело внутри if. И правда, ведь если условие всегда true, то и нет смысла его проверять. То же верно и для всегда ложных условий — код типа if (0) { ... } можно спокойно удалять.
А более «умные» компиляторы — например, новый компилятор TypeScript — будут такой код не оптимизировать, а бить программиста по рукам. Иногда и правда важно обращать на это внимание человека. Когда я проверял тестовые задания на позицию фронтендера, я встретил примерно такой код:
if (typingAccuracy => thresholdAccuracy) {
console.log("passed");
} Ну ты понял, да? Вместо <= наш фронтендер сделал лямбда-выражение. А с новым компилятором шансы на трудоустройство были бы выше 😉.
Такие ошибки выдаются не только в if. Если написать подобное в while или в тернарном операторе, компиляция тоже не пройдёт.
Прощай, while (true)? К счастью, нет. true, false, 1 и 0 воспринимаются как специальные значения и пропускаются компилятором. Их часто удобно использовать для отладки или тех же бесконечных циклов. Запрещать так писать — последовательно и безопасно, но жизнь это всем усложнило бы.
Похожие проверки теперь работают и для оператора ??. Только там проверяется не на true и false, а на null и не null. Соответственно, и специальных значений там нет — 0 ?? 1 или false ?? true тоже вызовет ошибку.
Импорт и экспорт бананов.
Майкрософт на примере бананов показали нам, что теперь можно импортировать и экспортировать даже невалидные идентификаторы — если заключить их в кавычки:
const banana = "🍌";
export { banana as "🍌" }; import { "🍌" as banana } from "./foo"
console.log(banana); // => 🍌 Это нужно для взаимодействия с другими языками. Например, с WebAssembly. Ведь каждый язык сам решает как называть переменные.
И о других изменениях.
О чём ещё стоит сказать:
- Новый флаг
--strictBuiltinIteratorReturnделает итераторы строже и исправляет один из косяков проверки типов в TypeScript. - Новый флаг
--noUncheckedSideEffectImportsпроверяет, что файл существует, когда пытаешься импортировать его. Даже если сам тайпскрипт не умеет работать с таким файлом (например, CSS модули). - И ещё один новый флаг
--noCheckотключает проверку типов. И просто выдаёт JS 😐. Звучит странно, но это иногда полезно и позволяет иметь два параллельных процесса — один для проверки типов, а другой для генерации кода.
О других апдейтах ты всегда можешь почитать в официальных release notes .