Repository: TypeScript
Issue: Surprising difference in nested calls inference from contextual type
Labels: Help Wanted,Possible Improvement

### 🔎 Search Terms

inference nested contextual type reverse mapped type parameter

### 🕗 Version & Regression Information

- This is the behavior in every version I tried

### ⏯ Playground Link

https://www.typescriptlang.org/play?ts=5.4.0-dev.20231208#code/C4TwDgpgBAggxsA9gJwEoQGYB4AqBJAOzAFdgA+KAXigG8AoKKOZCAQ2AgH4AuKACgCWRUr3zDgASioUAbogEATANx0AviroKIcADasWUDMQIIBiAoeSIAtgGEW7CLkIlyfBkwcdeg8aJekUpSy8goANHQSvPBIaJjO4mQaWrr60EYmwGYWAM4QwMRgAIxYHjgxKDlQEAAeHAQKVehwKApYOcDIQgDmYbAIKOjYBBAyEMhkZBFkgtZgOjm89IysA8g5PLQejADaANJQQlAA1hAgiBhQ5Ws5ALqiFev7tyqM6mpRV485Gi0EHVAWDliDpgEUqFA8gVinxllBVrFFltGIwAO4CYAACwCwF4GCsdi8ED4vlcvA6XQI3SCFBoqgkERRUHRWMQpBxeIJ9jYHBJNNo9MZUFUEXpGiBILBKgA9NKoAA9Th0TTaPQGDKmcyQ-KFABMpUY10R1TqEAaTW0rXanR6fUeQywIzGEymdBmAjmCyW8JumyNlWFn3961+5gBEtBuohUL1sI8CMqS22zIx2L8lhs3McJKEZMhNqp-LpDOTLMxbOAHIzhJ5xL4RcFHhFH3FEGBkZlcsVdCAA

### 💻 Code

```ts
type ActorRef<TInput> = {
  create?: (input: TInput) => void;
};

declare function fromCreate<TInput>(
  create: (input: TInput) => void,
): ActorRef<TInput>;

declare function setup1<
  TActors extends Record<string, ActorRef<never>>,
>(impls: {
  actors?: {
    [K in keyof TActors]: TActors[K];
  };
}): TActors;

const result1 = setup1({
  actors: {
    withInput: fromCreate((input: string) => {}),
    withoutInput: fromCreate(() => {}),
  },
});

result1;
// ^? const result1: { withInput: ActorRef<string>; withoutInput: ActorRef<unknown>; }

declare function setup2<
  TActors extends Record<string, ActorRef<never>>,
>(impls: { actors?: TActors }): TActors;

const result2 = setup2({
  actors: {
    withInput: fromCreate((input: string) => {}),
    withoutInput: fromCreate(() => {}),
  },
});

result2;
// ^? const result2: { withInput: ActorRef<string>; withoutInput: ActorRef<never>; }
```


### 🙁 Actual behavior

The only difference between those 2 calls is that `TActors` of the outer `setup` call is either iterated over (with `Identity`-like mapped type) or not.

Yet when this "noop" iteration is involved we infer the constraint of the `TInput` parameter in the nested `fromCreate` call. When the iteration is not involved then we infer `never`.

### 🙂 Expected behavior

I'd expect both of those calls to behave identically.

### Additional information about the issue

1. without the iteration the contextual type for this inner call is `ActorRef<never>` whereas with the iteration it's `TActors["withoutInput"]`
2. without the iteration we successfully `inferTypes` using `InferencePriority.ReturnType` from the instantiated `contextualType` but with the iteration we get `silentNeverType` for `TActors` and thus also `silentNeverType` for the whole indexed access. A `silentNeverType` is non-inferrable
3. One of those calls can gather inference candidates (and thus `ActorRef<never>` gets inferred) and the other one is not (so it defaults to its constraint).

It might not be worth fixing this. I figured out that it might still be interesting to raise this. **Maybe** a rule similar to the one introduced [here](https://github.com/microsoft/TypeScript/pull/56506) could be introduced somewhere? A more specific type (depending on the variance of the type parameter) could be picked up from the constraint type and the type inferred using `InferencePriority.ReturnType`. I'm not sure if that would work in practice though - just thinking out loud while writing, without giving this more thought 😅