TypeScript 5.5
Наконец-то зарелизили Typescript 5.5, который жду с апреля, с момента, когда его выкатили в бету. Обычно цикл бета-кандидат-релиз проходит за две-три недели, но тут затянулся на два месяца.
Фича, которую я “джва года ждал”:
Inferred Type Predicates
Наконец-то правильно работающие сужающие преобразования:
const c = [ 1, 2, 3, 'x', 'z' ]; // c: (number | string)[]
const x = c.filter(a => typeof a != 'string'); // x: number[]
Жаль только, что такой вариант не работает: c.filter(Boolean)
. Но всё равно это прорыв.
Иногда очень больно писать декларации, когда на вход сужающей функции подаётся такая каша из слитых вместе типов, что почти невозможно описать результат как is A
. Теперь он умеет вывестись самостоятельно:
type A = number;
type B = string;
// обычная запись. Так всегда и работало
function isA1(x: A | B): x is A {
return typeof x == 'number';
}
// а вот такой вариант раньше возвращал boolean, но теперь он полностью идентичен первому: `x is A`
function isA2(x: A | B) {
return typeof x == 'number';
}
Немного омрачает ситуацию, что сужение через typeof
внутреннего мембера уже не может справиться с выводом. Придётся что-то тут трикшотить, когда понадобится в реальной жизни:
type A = { a: number; b: string; };
type B = { a: string; b: string; };
function isA(x: A | B) { // выводится `boolean`
return typeof x.a == 'number';
}
Но проверки без typeof
работают:
type A = { a: number; b: string; mode: 'A' };
type B = { a: string; b: string; mode: 'B' };
function isA(x: A | B) { // выводится `x is A`
return x.mode == 'A';
}
Возможно, это поведение доработают чуть позже.
И ещё одна приятная фича, но не сказать, чтобы настолько же важная:
Control Flow Narrowing for Constant Indexed Accesses
Избавляет, наконец, от вороха ненужных временных переменных:
if (typeof obj[key] === "string") {
obj[key].toUpperCase();
}
// Раньше такой код генерировал ошибку и приходилось изворачиваться:
const temp = obj[key];
if (typeof temp === "string") {
temp.toUpperCase();
}