Пересечение типов в TypeScript
Даниил ШилоСегодня обсудим пересечение в TypeScript. Тема достаточно сложная для понимания, ибо пересечение в TypeScript сильно отличается от классического пересечения в дискретной математике.
Дискретная математика — раздел математики, который изучает множества, их поведение при различных условиях, а также логические функции и способы взаимодействия с ними.
Из дискретной математики для понимания операторов | и & нам понадобятся только два определения:
- Пересечением двух множеств называется множество, которому одновременно принадлежат элементы из первого и из второго множества.
- Объединением двух множеств называется множество, которому принадлежат только те элементы, которые есть или в первом, или во втором множестве.
В общем-то говоря, пересечением в TypeScript называется объект со всеми свойствами и методами, которые одновременно принадлежат и первому и второму типу, а объединением называется объект со всем свойствами или из первого, или второго типа😳
Говоря о пересечении, очень удобно представлять как два множества "сплющились" и создали одно большое множество с общими свойствами (что конечно, в дискретной математике называется не пересечением, а эквивалентными множествами, где два множества находятся в отношении подмножества друг-друга).

Простое правило👀: Если тяжеловато справится с дискретной математикой то, вот простое правило:
- Пересечение - когда все свойства объекта находятся и в первом, и во втором типе
- Объдинение - когда все свойства объекта находятся хотя бы в одном из типов
Именно поэтому, кстати, при объединении number | string, мы можем использовать только общие методы. Мы не можем использовать специфические методы, потому что не знаем в каком из множеств находимся😊
Вопрос: Почему все так запутано?! Почему при объединении мы можем использовать свойства, которые есть только в двух типах, разве это не пересечение?
Ответ: Черт бы побрал, но тут есть доля правды, единственное - когда разрабатывали язык, то ссылались не на свойства и методы типов, а на сами типы.
Пример: объединение строки и числа — число или строка. Вот и вся магия. TypeScript просто защищает вас, чтобы вы не использовали случаем метод для числа, когда работаете со строкой, вот и не дает использовать метод из прототипа числа.
Ещё пример: пересечение строки и числа?! Его нет! Мы только что заставили TypeScript найти значение, которое обязательно пересекается и в множестве чисел, и в множестве строк. TypeScript — не JavaScript, он не будет возвращать нам null (пустое множество), он просто вернет never (тип в который вообще ничего нельзя положить):

Когда мы пересекаем объекты, а не примитивы, то мы как бы даем понять TypeScript'у, что мы хотим специально сделать пересечение всех параметров, он скрещивает их в одно большое множество и делает все параметры из первого и второго объекта обязательными:
