microsoft / microsoft/TypeScript

tsserver hangs indefinitely when inferring return type of class method that passes this to a function with deeply nested conditional return type

Offen
#63,207 3 Kommentare 0 Reaktionen 0 zugewiesene Personen Auf GitHub ansehen

Dieses Issue hat noch niemand übernommen.

Bug Domain: check: Type Circularity
Vorherrschende Sprache
Go
Sterne
111k
Forks
14.3k
Ø Merge
2 T. 4 Std.
Gemergte PRs (30 T.)
132

Beschreibung

### 🔎 Search Terms

hang circular

### 🕗 Version & Regression Information

This behavior is present in TypeScript 5 and TypeScript 6 beta.

### ⏯ Playground Link

N/A — requires the remeda package (npm i remeda). Reproduction is a self-contained file below.

### 💻 Code

```ts
import { pick } from "remeda";

export class MyClass {
constructor(public readonly field: number) {}

// [bad] tsserver hangs indefinitely: no explicit return type
getIdentity() {
return pick(this, ["field"]);
}

// [good] works fine: explicit return type breaks the cycle
getIdentityFixed(): Pick {
return pick(this, ["field"]);
}
}
```

### 🙁 Actual behavior

`tsserver` becomes completely unresponsive. The editor (VS Code) loses all language service features (hover types, completions, diagnostics) until tsserver is manually restarted. No error is emitted; tsserver simply loops forever.

The cause is an undetected circular type inference chain. To infer the return type of `getIdentity()`, TypeScript must evaluate `PickFromArray` (remeda's `pick` return type). That involves `IsBoundedRecord` → `IsBounded>`. `KeysOfUnion` uses `UnionToIntersection`, which places `MyClass` in a contravariant function parameter position — forcing eager, non-deferred evaluation of the full structural type of `MyClass`. The full type of `MyClass` includes `getIdentity: () => `, whose inferred return type is what we started trying to compute. Because the cycle passes through ~5 distinct type alias instantiations, TypeScript's cycle-detection heuristics never fire, and the checker loops indefinitely instead of emitting a "circularly references itself" error.

### 🙂 Expected behavior

TypeScript should detect the circular inference and either:

- Emit a "Return type annotation circularly references itself" error (as it does for simpler cycles), or
- Fall back to any with a warning.

Either outcome is acceptable. The checker should never hang.

### Additional information about the issue

Workaround: add an explicit return type annotation to the method. This gives TypeScript the type of `MyClass.getIdentity()` upfront, preventing the cycle from forming.

Beitragsleitfaden

Beitragsleitfaden öffnen

Erste Schritte

  1. Lies das ganze Issue und danach den Beitragsleitfaden des Projekts.
  2. Schreib ins Issue, dass du es übernimmst — das erspart doppelte Arbeit.
  3. Forke das Repository und arbeite in einem Branch.
  4. Öffne einen Pull Request, der die Issue-Nummer nennt.

Rechercherichtung

Beginne damit, remeda zu installieren und die eigenständige TypeScript-Reproduktion mit tsserver auszuführen. Vergleiche den hängenden Fall mit inferiertem Rückgabetyp mit der expliziten Pick-Annotation und verfolge dann die Behandlung von Zirkularität rund um die gemeldete Kette aus PickFromArray, IsBoundedRecord, IsBounded, KeysOfUnion und UnionToIntersection. Fertig ist die Aufgabe, wenn tsserver nicht mehr hängt und entweder einen Fehler wegen eines zirkulären Rückgabetyps meldet oder mit einer Warnung auf any zurückfällt.

Vom Indexierungsmodell aus dem Issue-Text verfasst.

Bewertung

Tech-Stack
typescript
Bereich
compilers
Issue-Typ
Bug
Schwierigkeit
5/5
Geschätzter Aufwand
Über eine Woche
Aktivitätsstatus
Veraltet
Klarheit
Größtenteils klar
Anfängerfreundlichkeit
35/100

Neue Issues direkt in Ihr Postfach

Eine kurze Übersicht über anfängerfreundliche GitHub-Issues.