Синтаксические конструкции и операторы¶
Кроме типизации, TypeScript пытается сделать жизнь разработчиков более комфортной за счет добавления синтаксического сахара в виде операторов не существующих в JavaScript мире. Помимо этого, текущая глава поведает о неоднозначных моментах связанных с уже хорошо известными, по JavaScript, операторами.
Операторы присваивания короткого замыкания (&&=, ||=, &&=)¶
В большинстве языков, в том числе и JavaScript, существует такое понятие как составные операторы присваивания (compound assignment operators) позволяющие совмещать операцию присваивания при помощи оператора =
, с какой-либо другой допустимой операции (+-*/!
и т.д.) и тем самым значительно сокращать выражения.
let a = 1;
let b = 2;
a += b; // тоже самое что a = a + b
a *= b; // тоже самое что a = a * b
// и т.д.
Множество существующих операторов совместимы с оператором =
за исключением трех, таких часто применяемых операторов, как логическое И (&&
), логическое ИЛИ (||
) и оператор нулевого слияния (??
).
a = a && b;
a = a || b;
a = a ?? b;
Поскольку дополнительные синтаксические возможности лишь упрощают процесс разработки программ, благодаря комьюнити, в TypeScript появился механизм обозначаемый как операторы присваивания короткого замыкания. Данный механизм позволяет совмещать упомянутые ранее операторы &&
, ||
и ??
непосредственно с оператором присваивания.
let a = {};
let b = {};
a &&= b; // a && (a = b)
a ||= b; // a || (a = b);
a ??= b; // a !== null && a !== void 0 ? a : (a = b);
Операнды для delete должны быть необязательными¶
Представьте случай при котором в JavaScript коде вам необходимо удалить у объекта одно из трех определенных в нем полей.
let o = {
a: 0,
b: '',
c: true,
};
const f = (o) => delete o.b;
f(0); // удаляем поле b
Object.entries(o).forEach(([key, value]) =>
console.log(key, value)
);
/**
* log -
* -> a, 0
* -> b, true
*/
Задача предельно простая только с точки зрения динамической типизации JavaScript. С точки зрения статической типизации TypeScript, удаление члена объекта нарушает контракт представляемый декларацией типа. Простыми словами, TypeScript не может гарантировать типобезопасность, пока не может гарантировать существование членов объекта описанных в его типе.
type O = {
a: number;
b: string;
c: boolean;
};
let o: O = {
a: 0,
b: '',
c: true,
};
const f = (o: O) => delete o.b; // [*]
f(o); // удаляем поле b
/**
* [*] Error ->
* Oбъект o больше не отвечает
* типу O поскольку в нем нет
* обязательного поля b. Поэтому
* если дальше по ходу выполнения
* программы будут производится
* операции над удаленным полем,
* то возникнет ошибка времени выполнения.
*/
Поэтому TypeScript позволяет удалять члены объекта при помощи оператора delete
только в том случае, если они имеют тип any
, unknown
, never
или объявлены как необязательные.
type T0 = {
field: any;
};
const f0 = (o: T0) => delete o.field; // Ok
type T1 = {
field: unknown;
};
const f1 = (o: T1) => delete o.field; // Ok
type T2 = {
field: never;
};
const f2 = (o: T2) => delete o.field; // Ok
type T3 = {
field?: number;
};
const f3 = (o: T3) => delete o.field; // Ok
type T4 = {
field: number;
};
const f4 = (o: T4) => delete o.field; // Error -> The operand of a 'delete' operator must be optional.