Repository: TypeScript
Issue: IntelliSense/Autocomplete only resolves the generics in the first overload of a generic function with multiple overloads
Labels: Help Wanted,Possible Improvement

# Bug Report

<!--
  Please fill in each section completely. Thank you!
-->

### 🔎 Search Terms

Generic, Overload, Type Inference

### 🕗 Version & Regression Information

This is the behavior in every version I tried on the playground

### ⏯ Playground Link

[Playground link with relevant code](https://www.typescriptlang.org/play?ts=5.1.6#code/IYIwzgLgTsDGEAJYBthjAgQmgpgWR2gEtYAeASQBEEcAPCHAOwBMNIojGBzAPgQG8AUAgSh2cRADdgyAK44AKgE8ADjgBcoxkoDcg4UgD2jdrPiGoAChWyQyEgiLNNVAJQCAvoK+CUaDABysgC2IDhQBMRkVDT0TKwI7Jy8sQwsGNhg+IQc0ZR8QiLMOH5QOAjScoqqGgiMIWFQej4QNQiRuQBqMvLKaqQGHSQYdGkJmdlRpEncPADaALoANAYxo-EYQ7Bgc-Wh4QtzAERORwuCfAC8CACi9DDwpFs7e43LAo7OCDEe80eVvRqZz0gk4DCgADM4OUFFBDCoABZKABKhkMwQA8ioIERjGAnjlhqkNlhcFtpsRZosCgZgoTtppns19H50AhYfCkaj0QMRAB6PnshFEDAihAQBHlOlRDD2SDihHARAS8qyLJQBAqfw4DAAd0ljEcjCIOJkRAAXskFeVWWBBvSRnF0qSsuSZrxFhcBLSHYyHSCRLA8dAzBALJZ+AhpbkMB5NBzESi0ZjsbiTASZTx3IURAqRQA6aNE65F7Z6EQ+fmChSS77ULhMcIOYx5jAQ2SMeBpxwYNU4ZjiwypB6IfUkBFR+kIXU4ADkZQQyDRAGsrWGkIruOUwEOJUrrRUeuVWmoDAKkMBDWEjRDwmUByBcAOWyrJzLFyLEFr0P2jdODUgZRKmutacJAl6wOUhgQgetr5kKx5tGUSRdsYZ6Ci2MTBMAy46oksgLnuyq1n2GrGMgSg0Iw4IYJenwINBohvrkCr7rqaCatqA7rq+YEQBB5T7rAQE4sY+boQgGKSOES7AAOACCmj8bhGCvowOC6oeVQGFkEDkgYIhrE6CTPLsDQHMcpzLAZCDdFUfTlOszpbHZgL9M8Sx1jwBg8JYTguJQnkArUrnVGoriaJIhhOOWCDnlJMmGHJWBKTheHAAg7adqJhpEeKaWqbWhjIAOwVaAOZQQARJgHupmnBTphD6bmdbEs5DpmfsUCHCczBnCsLWhQ5bUmfSQ01BmMaeVQ3kiL5-l1kFR6aJYxXMKFmjjeFCCXHwW04BFFTRcwAaJE19K8rmRljJsHWvBZvX9TZ+0jbdUT7ZNwzTfkPl+V8VBLVUGJQAAYh2qGMJtR7DQAPgglirSVG22dDNTuLtKP2Wjh1RU43otee+ZEwYXg+EGJjEVa1x1eycKJtywQRj6MqaLsGkIEEXVbJYRwMJARyuJ5NOc403O8zqEAAEwC9ZHiuHoErJPmuli3zEAC3oQA)

(To see the issue in action, go to line 55 and add a comma to the parameters to trigger the completion and look at both overload options)

### 💻 Code

```ts
abstract class BaseMetric<ID extends string> {
  abstract valueType: any;

  constructor(public id: ID) {}
}

class NumberMetric<ID extends string> extends BaseMetric<ID> {
  declare valueType: number;
}

type MetricValueType<
  Metrics extends BaseMetric<string>[],
  ID extends Metrics[number]["id"]
> = Extract<Metrics[number], { id: ID }>["valueType"];

interface TrophyRoomOptions<Metrics extends BaseMetric<string>[]> {
  metrics: Metrics;
}

class TrophyRoom<
  // This is the metrics list that the user passes when initializing the class
  Metrics extends BaseMetric<string>[]
> {
  metrics: Metrics;

  constructor({ metrics }: TrophyRoomOptions<Metrics>) {
    this.metrics = metrics;
  }

  // The ID generic on this function is used to extract which metric we're looking to change so that the value type
  // can be inferred based on the metrics list passed in when creating the instance of the class. The type restriction
  // on ID makes sure that the user only enters an id of a metric that was passed to the instance at creation.
  // Overload A: takes the new value
  setMetric<
    ID extends Metrics[number]["id"],
    ValueType extends MetricValueType<Metrics, ID>
  >(id: ID, value: ValueType): void;
  // Overload B: takes a function that takes the old value and returns the new value
  setMetric<
    ID extends Metrics[number]["id"],
    ValueType extends MetricValueType<Metrics, ID>
  >(id: ID, value: (oldValue: ValueType) => ValueType): void;

  setMetric<
    ID extends Metrics[number]["id"],
    ValueType extends MetricValueType<Metrics, ID>
  >(id: ID, valueOrFunction: ValueType | ((oldValue: ValueType) => ValueType)): void {
    // ...
  }
}

const thing = new TrophyRoom({
  metrics: [new NumberMetric("test"), new NumberMetric("test2")],
});
```

### 🙁 Actual behavior

In the IntelliSense/Autocomplete for `thing.setMetric()` (when specifying "test" as the first argument), the type of the first overload gets simplified to:
```ts
setMetric(id: "test", value: number): void
```
and the type of the second overload doesn't get simplified at all
```ts
setMetric<ID extends "test" | "test2", ValueType extends MetricValueType<(NumberMetric<"test"> | NumberMetric<"test2">)[], ID>>(id: ID, value: (oldValue: ValueType) => ValueType): void
```

This behavior is not based on the second overload being more complex, if you swap the positions of the two overloads, the first one will get simplified to:
```ts
setMetric(id: "test", value: (oldValue: number) => number): void
```
while the second one doesn't get simplified
```ts
setMetric<ID extends "test" | "test2", ValueType extends MetricValueType<(NumberMetric<"test"> | NumberMetric<"test2">)[], ID>>(id: ID, value: ValueType): void
```

### 🙂 Expected behavior

Both overloads should get simplified to:
```ts
setMetric(id: "test", value: number): void
```
and
```ts
setMetric(id: "test", value: (oldValue: number) => number): void
```
regardless of their order in the overloads

### Workaround

While it is possible in this case to just use a single definition for the method instead of the overloads:
```ts
setMetric<
  ID extends Metrics[number]["id"],
  ValueType extends MetricValueType<Metrics, ID>
>(id: ID, valueOrFunction: ValueType | ((oldValue: ValueType) => ValueType)): void
```
having the two overloads makes it clearer that the method has two separate behaviors based on whether you're passing a raw value or a function to update to the value.