Repository: TypeScript
Issue: Reverse mapped type with a circular type param sometimes not treated as partially inferrable
Labels: Needs Investigation

# Bug Report

### 🔎 Search Terms

reverse mapped types, circular type, partially inferrable

### ⏯ Playground Link

[Playground link with relevant code](https://www.typescriptlang.org/play?ts=4.6.2#code/C4TwDgpgBAggdiAYgVzgY2ASwPZygXigAoA6MgQwCcBzAZwC4pyEBtAXQEoCA+JhAbgBQg0JCgBJOADMIlAHJVK2AO4RawADwAVXoS1QIAD2AQ4AE1p8QgqFAD8UfUZPnL8JKgw44N2-ce+toxOxqYWUNgARgBWEBiB-pIy8ooqasAA8jFxmjoJwb6McBAAbrJCIuDQSbIKlEqq6lmxGNq6UADevpQQ5Ga4ADYgUCwA0lCYeADWECDYUo5sjDUp9Wnq2mNs3EIAvhWi0ADCuFKY1NoA4gNR5AMANI4AysDkJgRQAApKYFc3kXdHgAidRvNRA7jtLq2UEmBidBIsF5g0azCbTWbzZ6vExLBF+Py4OyMDr7BJk2xk3ZQABk+PRmCwd0YMzmCy0yJMewOVS+P20j1G7XGzjCllZWP0Di0WygRVK5WEaFw6igaB6YIAsuQ0AALSbQQjaE7Sc4GUKuKAms4XLTW86Qoi+AD6ytN1GW0lqqUamWyrTtpwdgg4jBK2EwZh4nTJgnVvRM2r1BqI0IZTIGjCBkHMk2oQPuvlhahJCRzZjzpYJtlwVertn6xSIXDT9dsPWAyEoeCBcGwABE3uQgUI21BdoX6xPyZPx4XdhwhEA)

### 💻 Code

```ts
type AnyFunction = (...args: any[]) => any;

type InferNarrowest<T> = T extends any
  ? T extends AnyFunction
    ? T
    : T extends object
    ? InferNarrowestObject<T>
    : T
  : never;

type InferNarrowestObject<T> = {
  readonly [K in keyof T]: InferNarrowest<T[K]>;
};

type Config<TGlobal, TState = Prop<TGlobal, "states">> = {
  states: {
    [StateKey in keyof TState]: {
      on?: {};
    };
  };
} & {
  initial: keyof TState;
};

type Prop<T, K> = K extends keyof T ? T[K] : never;

const createMachine = <TConfig extends Config<TConfig>>(
  _config: InferNarrowestObject<TConfig>
): void => {};

createMachine({
  initial: "pending",
  states: {
    pending: {
      on: {
        done() {
          return "noData";
        },
      },
    },
  },
});

```

### 🙁 Actual behavior

Inferred signature is:
```ts
const createMachine: <Config<{
    initial: "pending";
    states: unknown;
}, unknown>>(_config: InferNarrowestObject<Config<{
    initial: "pending";
    states: unknown;
}, unknown>>) => void
```

### 🙂 Expected behavior

`states: unknown` shouldn't be inferred here, the reverse mapped type should be able to infer an object literal type~. The type param should be inferred as something like:
```ts
const createMachine: <{
    initial: "pending";
    states: {
        pending: {
            on: {
                done: () => "noData";
            };
        };
    };
}>(_config: InferNarrowestObject<{
    initial: "pending";
    states: {
        pending: {
            on: {
                done: () => "noData";
            };
        };
    };
}>) => void
```

We can simplify the repro a little bit, but it will then yield an error at a different position and I can't verify right now if the underlying issue is exactly the same in this case (although from what it looks like the root cause is super similar):
[TS playground without conditional type applied at the argument position](https://www.typescriptlang.org/play?ts=4.6.2#code/C4TwDgpgBAwg9gOwGYEsDmAeAKgcQDZwBGAhngDRRYDKwxw0AvFAAoBOcY2+RpFARAGda9AXwB8YqEwDeAKChQhdCAIBcUOQoUBtGsoDSEEFBQIoAayNwklPfQC66zVoWIA-E4C+AbnlaffgGeUABkGn6mKMAopOqWINa2whC+AbKgkCzsnFgU+pJM+lAQAB70CAAmAhZWNlhQbpTa+vZQ6ggQAG4QrL6yAMaIQlD9rBDKALLE-QAWpoxQ2PDI6MVlEJXVy6iYWNvoEgAUfgD6gyto6nuIO7IAlOqdcCgVUpLSaaPj9FOz84fOSLRWJQPiQSqmNB8Mh+JQiJx+BTgiqQhEuVwINHohQVRAQQ53cLYlxjYAAV1YZj4CDgABE6MQ+L5iVBPDDsWzEaz2dzZJ47r4gA)

Note that we can fix both playground by using an arrow function instead of a method (probably related to a possible "hidden" `this` type param that makes this context sensitive in the case of a method). 

The first one can be fixed by adding a dummy property to the object containing a method (this makes the object partially inferrable):
[TS playground with a dummy property added](https://www.typescriptlang.org/play?ts=4.6.2#code/C4TwDgpgBAggdiAYgVzgY2ASwPZygXigAoA6MgQwCcBzAZwC4pyEBtAXQEoCA+JhAbgBQg0JCgBJOADMIlAHJVK2AO4RawADwAVXoS1QIAD2AQ4AE1p8QgqFAD8UfUZPnL8JKgw44N2-ce+toxOxqYWUNgARgBWEBiB-pIy8ooqasAA8jFxmjoJwb6McBAAbrJCIuDQSbIKlEqq6lmxGNq6UADevpQQ5Ga4ADYgUCwA0lCYeADWECDYUo5sjDUp9Wnq2mNs3EIAvhWi0ADCuFKY1NoA4gNR5AMANI4AysDkJgRQAApKYFc3kXdHgAidRvNRA7jtLq2UEmBidBIsF5g0azCbTWbzZ6vExLBF+Py4OyMDr7BJk2xk3ZQABk+PRmCwd0YMzmCy0yJMewOVS+P20j1G7XGzjCllZWP0Di0WygRVK5WEaFw6igaB6YIAsuQ0AALSbQQjaE7Sc4GUKuKAms4XLTW86Qoi+AD6ytN1GW0lqqUamWyrTtpwdgg4jBK2EwZh4nTJgnVvRM2r1BqI0IZTIGjCBkHMk2oQPuvlhahJCRzZjzpYJtlwVertjhwEYABYAEyF+u2frFIhcNOdqA9YDISh4IFwbAAETe5CBQgHuw71cX5KXK92HCEQA)

Especially given that a dummy property fixes the problem it looks like a weird design limitations.

What I've learned when debugging this:
1. methods + functions with arguments are context sensitive and in `checkFunctionExpressionOrObjectLiteralMethod` they return `anyFunctionType`
2. `anyFunctionType` has `ObjectFlags.NonInferrableType` on it
3. this flag is "propagating" and thus is set on the "parent" object
4. `uninstantiatedType` for the `on` property of this argument gets computed to `{}` (so it's empty~)
5. and thus it doesn't pass `isPartiallyInferableType` check when resolving the structure of the reverse mapped type, since the object has `ObjectFlags.NonInferrableType` on it AND there are no other properties that would be treated as partially inferrable
6. since no structure is resolved for this mapped type the `unknown` is returned for the `states` property
7. this in turn makes `initial` property to error because `keyof unknown` is `never`

while a workaround is "known" here (we've learned this hard way though)~ the whole thing still has some problems because we can't provide a param type for the arrow functions contained in `on` property because once we add any unannotated params to an arrow function it becomes context-sensitive and results in a similar problem:
[TS playground with context-sensitive arrow function](https://www.typescriptlang.org/play?ts=4.6.2#code/C4TwDgpgBAggdiAYgVzgY2ASwPZygXigAoA6MgQwCcBzAZwC4pyEBtAXQEoCA+JhAbgBQg0JCgBJOADMIlAHJVK2AO4RawADwAVXoS1QIAD2AQ4AE1p8QgqFAD8UfUZPnL8JKgw44N2-ce+toxOxqYWUNgARgBWEBiB-pIy8ooqasAA8jFxmjoJwb6McBAAbrJCIuDQSbIKlEqq6lmxGNq6UADevpQQ5Ga4ADYgUCwA0lCYeADWECDYUo5sjDUp9Wnq2mNs3EIAvhWi0ADCuFKY1NoA4gNR5AMANI4AysDkJgRQAApKYFc3kXdHgAidRvNRA7jtLq2UEmBidBIsF5g0azCbTWbzZ6vExLBF+Py4OyMABKcWwlDMGnUlEm1EeRCo1EYNLpXHwvFZcGoOwS+18-N2UAAZPj0ZgsHdGDM5gstMiTHsDlUvj9tI9Ru1xs4wpYZVj9A4tFsoEVSuVhGhcOooGgemCALLkNAAC0m0EI2hO0nOBlCrig3rOFy0QfOkKIvgA+lafcyJNJaqlGplsq1Q6dw4IOIwSthMGYeJ1+YI7b0TE7Xe6iNDxZKBowgZBzHSgfdfLC1Ixa7Zm2Y6d2ErZcIOCQT+sVGIyaOzeD2x7YesBkJQ8EC4NgACJvchAoQL2y7dsLo9849QU+7DhCIA)

Related to https://github.com/microsoft/TypeScript/issues/40439