Почему у пересечения функций такой ReturnType?

При работе с TypeScript иногда возникает необходимость объединять или пересекать типы функций. В качестве примера рассмотрим пересечение типов двух функций:

type FunctionA = (x: number) => string;
type FunctionB = (y: string) => number;

type FunctionAB = FunctionA & FunctionB;

В результате получаем тип FunctionAB, который будет являться пересечением типов FunctionA и FunctionB. То есть, тип FunctionAB должен быть таким, что он одновременно является функцией с аргументом типа number и возвращаемым значением типа string, а также функцией с аргументом типа string и возвращаемым значением типа number.

Теперь рассмотрим ReturnType этого пересечения:

type ReturnTypeAB = ReturnType<FunctionAB>;

В этом случае ReturnType возвращает тип результата FunctionAB, то есть string & number. Проблема здесь в том, что пересечение string & number не имеет смысла и не может быть представлено в языке TypeScript.

При попытке скомпилировать данный код, TypeScript выдаст ошибку:

Type error: Type 'string & number' does not satisfy the constraint 'string | number'.

Это связано с тем, что пересечение типов приводит к созданию нового типа, который является пересечением всех свойств и методов обоих типов. В данном случае, пересечение string & number не имеет общих свойств и методов, поэтому TypeScript не может представить такой тип.

Такая ситуация может возникнуть, когда пересекаются функции с разными возвращаемыми типами. В данном случае, TypeScript не может точно определить, какой будет тип результата пересечения, поэтому возвращает пересечение типов, которые не имеют общих свойств и методов.

Чтобы избежать такой ситуации, необходимо явно указывать тип результата при объединении или пересечении функций. Например, в данном случае можно указать тип результата FunctionAB как string | number:

type FunctionAB = (x: number) => string | number;

В этом случае, ReturnType<FunctionAB> будет возвращать тип string | number, что более понятно и представимо в TypeScript.