microsoft / microsoft/TypeScript

Refinement type inference quirk with implicitly typed `let x`

Offen
#56,097 5 Kommentare 0 Reaktionen 0 zugewiesene Personen Auf GitHub ansehen

Dieses Issue hat noch niemand übernommen.

Bug Domain: check: Control Flow Help Wanted
Vorherrschende Sprache
Go
Sterne
111k
Forks
14.4k
Ø Merge
1 T. 19 Std.
Gemergte PRs (30 T.)
117

Beschreibung

🔎 Search Terms

refinement narrow let any

🕗 Version & Regression Information
  • This changed between versions 3.9.7 and 4.0.5; the behavior is present in every version from 4.0.5 to 5.3 nightly; I skimmed the whole FAQ document and didn't find anything relevant
⏯ Playground Link

https://www.typescriptlang.org/play?ts=5.3.0-dev.20231013#code/C4TwDgpgBAsiAq5oF4oG8qkgLigcgEE8oBfKAH3UyVzwCFiSBuAKBYDMBXAOwGNgAlgHtuUdgAoAhgCcA5rjiJIASnQsoGqABsIwKAA9Wmg1FQzZRzQPZRx+gHRYUyVITyq06zWQhaAztDWtg5Opi74DB5eGj7+0J7Gxjp6APq43BAAbhDSpgaWMSwkLEA

💻 Code
type MyType = { type: 'A' } | { type: 'B' };

function f(arg: MyType) {
    let x;
    x = arg;
    if (x.type === 'A') {
    } else if (x.type === 'B') {
    } else {
        let _: never = x;
    }
}
🙁 Actual behavior
error TS2322: Type '{ type: "B"; }' is not assignable to type 'never'.

9         let _: never = x;
              ~

This is wrong for two reasons:

  • In the world of perfect type inference, x should be narrowed to never at this point
  • Even acknowledging that there could be some practical limitations, the behavior is not consistent.
    image
    First conditional successfully eliminates the "A" variant:
    image
    But second conditional fails to eliminate the "B" variant:
    image
🙂 Expected behavior

Ideally, this shouldn't be an error at all.

However, given that control-flow-based type inference has its limitations, perhaps some kind of spurious error is inevitable. In that case, it probably should be more like Type 'MyType' is not assignable to type 'never' rather than Type '{ type: "B" }' is not assignable to type 'never'.

Additional information about the issue

Practical impact of this issue is small. There is an easy workaround of adding an explicit type annotation (let x: MyType;).

However, this asymmetry, that the last conditional fails at narrowing when exactly the same conditional before that succeeds, bothers me. I'm reporting this because it could be a symptom of a more general implementation defect.

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, das TypeScript Playground-Beispiel zu reproduzieren, und vergleiche das Verhalten zwischen den gemeldeten Versionen. Untersuche die auf dem Kontrollfluss basierende Typinferenz und -eingrenzung für ein implizit typisiertes let, das aus MyType zugewiesen wird; abgeschlossen ist die Untersuchung, wenn der abschließende else-Zweig konsistent eingegrenzt wird oder die vereinbarte Diagnose erzeugt, ohne die vorherige Eingrenzung zu beeinträchtigen.

Vom Indexierungsmodell aus dem Issue-Text verfasst.

Bewertung

Tech-Stack
typescript
Bereich
compilers
Issue-Typ
Bug
Schwierigkeit
4/5
Geschätzter Aufwand
3-5 Tage
Aktivitätsstatus
Veraltet
Klarheit
Klar beschrieben
Anfängerfreundlichkeit
35/100

Neue Issues direkt in Ihr Postfach

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