Why does an intersection change when the types are reordered? Why does an intersection change when the types are reordered? typescript typescript

Why does an intersection change when the types are reordered?


Taken from docs:

When inferring from a type with multiple call signatures (such as the type of an overloaded function), inferences are made from the last signature (which, presumably, is the most permissive catch-all case). It is not possible to perform overload resolution based on a list of argument types.

More explanation you can find here

When you made intersection of two functions - it is mean you made an overloading.

See next example:

type A = (a: number) => numbertype B = (b: string) => stringtype C = (c: any) => anydeclare var foo: A & B & Cfoo(2) // numberfoo('2') // stringfoo({}) // any 

Above code is equal to:

    function bar(a: string): string;    function bar(a: number): number;    function bar(a: any): any;    function bar(a: number | string | any) {        return null as any    }    bar(2); // number    bar('2') // string    bar({}) // any

Please keep in mind, that I put less specific a:any at the end. And it works as expected.

But, what if I put it at the beginning:

    function bar(a: any): any;    function bar(a: string): string;    function bar(a: number): number;    function bar(a: number | string | any) {        return null as any    }    bar(2); // any    bar('2') // any    bar({}) // any}

All ReturnTypes are any. Because less specific overloading is at the beginning.

Same here:

type A = (a: number) => numbertype B = (b: string) => stringtype C = (c: any) => anydeclare var foo: C & B & Afoo(2) // anyfoo('2') // anyfoo({}) // any 

UPDATE

Let's dig into ConstructorParameters. What does it mean?

// this is what ConstructorParameters doing under the hoodtype Check = A extends (a: infer A) => any ? A : never // numbertype Check2 = (A & B) extends (a: infer A) => any ? A : never // stringtype Check3 = (A & B & C) extends (a: infer A) => any ? A : never // any

It just takes the last intersected item and infers it's parameters.

So if I put A as a last item, it will infer only A params:

    type Check4 = (C & B & A) extends (a: infer A) => any ? A : never // number

So if you are doing intersection of functions - you should treat is as overloading.

Edge case: if you have function types with generics - intersection it might not work. I don't know/understand why.