It is true that the situation may be confusing regarding the arguments of types of function, when these functions are combined together.
@Bishwajitjha is not totally wrong in trying to explain it with the Set theory, even though simple diagrams may be enough.
Intersection F1 & F2 of function types

const example1: F1 & F2
example1 function can be called both as F1 and as F2. Therefore it corresponds to a TypeScript function overload:
- you can execute it as if it were an F1 (
example1("Hello", "World")),
- or as if it were an F2 (
example1(1, 2)),
- but you cannot mix (error for
example1("Hello", 2))
It is even easier to see how TypeScript handles the F1 & F2 intersection as an overload, if they had return types:
// Overload demonstration
type F1b = (a: string, b:string) => string;
type F2b = (a: number, b:number) => number;
declare const example1b: F1b & F2b;
const r1b1 = example1b("foo", "bar") // string
parseInt(r1b1) // Okay
r1b1.toFixed() // Error! Property 'toFixed' does not exist on type 'string'
const r1b2 = example1b(1, 2) // number
parseInt(r1b2) // Error! Argument of type 'number' is not assignable to parameter of type 'string'.
r1b2.toFixed() // Okay
declare const r1b3: ReturnType<F1b & F2b> // When TS must choose, it uses the last overload => number
parseInt(r1b3) // Error! Argument of type 'number' is not assignable to parameter of type 'string'.
r1b3.toFixed() // Okay
declare const r1b4: ReturnType<F2b & F1b> // When TS must choose, it uses the last overload => string
parseInt(r1b4) // Okay
r1b4.toFixed() // Error! Property 'toFixed' does not exist on type 'string'
Union F1 | F2 of function types

const example2: F1 | F2
Here it is more complex, because it does not match a specific TypeScript construct.
example2 may be just an F1, or just an F2, or an overload of both. Because the union does not provide any further information, when we try using example2, we must account for all these possibilities simultaneously: https://www.typescriptlang.org/docs/handbook/2/everyday-types.html#working-with-union-types
- as an F1, it would need both its arguments as
string
- as an F2, it would need both its arguments as
number
- as an F1 & F2, it can have either both as
string or both as number (previous section)
Therefore both arguments must be at the same time string and number, i.e. string & number. Which is unfortunately never as described by @SilvioMayolo.
Note that we could still have a "valid" call to example2 function:
// Using never type...
declare const arg: string & number; // Inferred as never
example2(arg, arg); // Okay!.. but should never be reached
At least, the return type (if they had one) follows the intuition:
declare const r2b: ReturnType<F1b | F2b> // string | number
parseInt(r2b) // Error! Argument of type 'string | number' is not assignable to parameter of type 'string'. Type 'number' is not assignable to type 'string'.
r2b.toFixed() // Error! Property 'toFixed' does not exist on type 'string | number'. Property 'toFixed' does not exist on type 'string'.
What about the actual function that was assigned?
Unfortunately, even though we assign an actual function that can accept more diverse argument types (it could even have been unions with boolean, null, an arbitrary type, etc.; provided that it can be called one way or another as an F1, or alternatively as an F2), we lose the more tolerant behaviour by explicitly specifying the type of example2.
// Losing information of the actual function
const fn1d = (a: string | number | boolean, b: string | number | {a: number}) => {}
fn1d(true, {a: 1}) // Okay
const example1d: F1 & F2 = fn1d // Okay
example1d(true, {a: 1}) // Error! No overload matches this call. Overload 1 of 2, '(a: string, b: string): void', gave the following error. etc.
const example2d: F1 | F2 = fn1d // Okay
example2d(true, {a: 1}) // Error! Argument of type 'boolean' is not assignable to parameter of type 'never'.
In the case of F1 | F2 union, the situation would have been different if we had assigned a narrower type instead, e.g. (a: string, b: string) => {}: here TypeScript would have followed the assignment, and inferred that we have a narrower type (as exactly described in https://www.typescriptlang.org/docs/handbook/2/narrowing.html#assignments)
// Narrower type assignment
const example2c: F1 | F2 = (a: string, b: string) => {}
example2c("Hello", "World") // Okay
example2c(1, 2) // Error! Argument of type 'number' is not assignable to parameter of type 'string'.
example2c("Hello", 2) // Error! Argument of type 'number' is not assignable to parameter of type 'string'.
What about example3 to example7?
As pointed out by @SilvioMayolo's comment, these examples show how assignment is as expected.
Going further, we could describe their usage as well, but they would still be close to intuition:
declare const example8: {a: string} & {a: number}
const a = example8.a // never
parseInt(a) // Okay... but should never be reached
a.toFixed() // Property 'toFixed' does not exist on type 'never'.
declare const example9: {a: string} | {a: number}
const a9 = example9.a // string | number
parseInt(a9) // Error! Argument of type 'string | number' is not assignable to parameter of type 'string'. Type 'number' is not assignable to type 'string'.
a9.toFixed() // Error! Property 'toFixed' does not exist on type 'string | number'. Property 'toFixed' does not exist on type 'string'.
Only arguments of combined function types are really misleading.
TypeScript Playground