Repository: TypeScript
Issue: Type inference of generics does not work only when callback takes argument
Labels: Bug

<!-- 🚨 STOP 🚨 𝗦𝗧𝗢𝗣 🚨 𝑺𝑻𝑶𝑷 🚨

Half of all issues filed here are duplicates, answered in the FAQ, or not appropriate for the bug tracker. Even if you think you've found a *bug*, please read the FAQ first, especially the Common "Bugs" That Aren't Bugs section!

Please help us by doing the following steps before logging an issue:
  * Search: https://github.com/Microsoft/TypeScript/search?type=Issues
  * Read the FAQ: https://github.com/Microsoft/TypeScript/wiki/FAQ

Please fill in the *entire* template below.
-->

I encountered a strange behavior of type inference about the generic arguments and intersection type. The error described below occurs only when the `strictFunctionTypes` option is enabled.

---

<!-- Please try to reproduce the issue with `typescript@next`. It may have already been fixed. -->
**TypeScript Version:**

Version 3.3.0-dev.20181221

<!-- Search terms you tried before logging this (so others can find this issue more easily) -->
**Search Terms:**

- `strictFunctionTypes`
- `argument intersection type`
- `generic argument`
- `generic intersection type`

**Code**

tsconfig.json:

```json
{
  "compilerOptions": {
    "moduleResolution": "node",
    "target": "es6",
    "module":"commonjs",
    "strictFunctionTypes": true,
    "outDir": "dist"
  },
  "include": ["*.ts"]
}
```

source:

```ts
const run = <P1, P2>(
  makeProps1: (s: string) => P1,
  makeProps2: () => P2,
  useBoth: (props: P1 & P2) => void
) => {};

const foo = (props: { n: number; b: boolean }) => {};

// This works as expected.
run(() => ({ n: 1 }), () => ({ b: true }), foo);

// But if the first argument function takes a parameter `s`, it results in a compile error.
run(s => ({ n: 1 }), () => ({ b: true }), foo);
```

**Expected behavior:**

The type of `run` is inferred correctly from `run(s => ({ n: 1 }), () => ({ b: true }), foo)` as below and the code compiles.

```
const run: <{ n: number; }, { b: boolean; }>(makeProps1: (s: string) => { n: number; }, makeProps2: () => { b: boolean; }, useBoth: (props: { n: number; } & { b: boolean; }) => void) => void
```

This type is generated from `run(() => ({ n: 1 }), () => ({ b: true }), foo)`. I copied it from Playground's tooltip.

**Actual behavior:**

It results in the compile error.

output of `npx tsc`:

```
repro.ts:9:43 - error TS2345: Argument of type '(props: { n: number; b: boolean; }) => void' is not assignable to parameter of type '(props: { b: boolean; }) => void'.                                  
  Types of parameters 'props' and 'props' are incompatible.
    Property 'n' is missing in type '{ b: boolean; }' but required in type '{ n: number; b: boolean; }'.                                                                                                 

9 run(s => ({ n: 1 }), () => ({ b: true }), foo);
                                            ~~~

  repro.ts:7:23
    7 const foo = (props: { n: number; b: boolean }) => {};
                            ~
    'n' is declared here.


Found 1 error.
```

This is because the return type of `makeProps1` is inferred as `{}` instead of `{ n: number; }`.

```
const run: <{}, { b: boolean; }>(makeProps1: (s: string) => {}, makeProps2: () => { b: boolean; }, useBoth: (props: { b: boolean; }) => void) => void
```

**Playground Link:** <!-- A link to a TypeScript Playground "Share" link which demonstrates this behavior -->

[Here][playground]. Note that this problem occurs only when the `strictFunctionTypes` option is enabled.

[playground]: http://www.typescriptlang.org/play/#src=const%20run%20%3D%20%3CP1%2C%20P2%3E(%0A%20%20makeProps1%3A%20(s%3A%20string)%20%3D%3E%20P1%2C%0A%20%20makeProps2%3A%20()%20%3D%3E%20P2%2C%0A%20%20useBoth%3A%20(props%3A%20P1%20%26%20P2)%20%3D%3E%20void%0A)%20%3D%3E%20%7B%7D%3B%0A%0Aconst%20foo%20%3D%20(props%3A%20%7B%20n%3A%20number%3B%20b%3A%20boolean%20%7D)%20%3D%3E%20%7B%7D%3B%0A%0Arun(s%20%3D%3E%20(%7B%20n%3A%201%20%7D)%2C%20()%20%3D%3E%20(%7B%20b%3A%20true%20%7D)%2C%20foo)%3B%0A

**Related Issues:** <!-- Did you find other bugs that looked similar? -->

I could not find.

**Other Investigation**:

In the code below, the type inference works as expected:

```typescript
const run2 = <P1, P2>(
  makeProps1: (s: string) => P1,
  makeProps2: () => P2,
  useProps1: (p: P1) => void,
  useProps2: (p: P2) => void
) => {};

// The first argument function takes a parameter `s` but it does not change the type inference behavior.
run2(
  s => ({ n: 1 }),
  () => ({ b: true }),
  (p1: { n: number }) => {},
  (p2: { b: boolean }) => {}
);
```

So it seems that the error only occurs when the generic types (`P1`, `P2`) are used as intersection type.