microsoft / microsoft/TypeScript

Assertion methods (`asserts this is`) are not CFA'd without error

Offen
#41,552 0 Kommentare 0 Reaktionen 0 zugewiesene Personen Auf GitHub ansehen

Dieses Issue hat noch niemand übernommen.

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

Beschreibung

TypeScript Version: 4.0.5, 4.1.0-beta, 4.2.0-dev.20201112

Search Terms:

  • Multiple assertion methods
  • "asserts this is"
  • assertion "cfa"

Code

class X<T, Locked extends boolean> {
    public x: null | T | (Locked extends true ? 1 : 2) = null

    public assert<U>(): asserts this is X<U, Locked> { }
    public lock(): asserts this is X<T, true> {}
}

const x: X<string | number, false> = new X<string | number, false>()

x.assert<string>()
// x is X<string, false> here

x.lock()

Expected behavior:

Either:

  • After x.lock(), x is narrowed to X<string, true>
  • Or, the x.lock() line throws at compile-time due to not being CFA'd

Actual behavior:

After x.lock(), x is narrowed to X<string, false> & X<string | number, true>.

Playground Link: https://www.typescriptlang.org/play?ts=4.2.0-dev.20201112#code/MYGwhgzhAEAaA8AVANNAMge2AawKYBNpcAPAF1wDt8YAjDDEXMCgPmgG8BYAKGj+gAOAVxogAlsGjEAXNApCQIaAB9oiFdAAUmHASJlK1aKQBOQ3NAD80AIzRZAJgCU0ALxyFIHj36CR4yUgIXBNSeABVFk0nWSCQ0hhSAAsxGFS4CNQdPHw2dmgAXx9+YVEJaBAsbGjYqHjElLSYBBRjM1w8ou4unmAMCghSKVkEQZMxCgBzDXkAWxoQ1AAzMBBgtncKXAB3DLGJ6dU5hZNl1fXo725iADo40Ph9qainHgB6N6lodNHTA7O1h1oEkQrgrvhcKAwCYLEshBRgKQxP0KlUkFEAG4jJCoOgMJisGLQe4JaAY77NHFtcwsK63So4S7cIA

Analysis:

x being typed as X<string, false> & X<string | number, true> shows that the x.lock() narrows from the original type (X<string | number, false>) instead of the narrowed type at that position (X<string, false>).

If instead a "top-level" assertion function is used the type is properly narrowed:

class X<T, Locked extends boolean> {
    public x: null | T | (Locked extends true ? 1 : 2) = null

    public assert<U>(): asserts this is X<U, Locked> { }
    public lock(): asserts this is X<T, true> {}
}

const x: X<string | number, false> = new X<string | number, false>()

x.assert<string>()
// x is X<string, false> here

declare function lock<T>(v: X<T, boolean>): asserts v is X<T, true>
lock(x)

Playground

This leads me to believe this is an issue with the x.lock() call not being CFA'd, in which case the correct behavior would be to throw ts(2775) on the x.lock() line.

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

Führen Sie zunächst die bereitgestellte TypeScript Playground-Reproduktion aus und vergleichen Sie die Kontrollfluss-Narrowing nach x.assert<string>() und x.lock(). Untersuchen Sie die Behandlung von Methoden mit asserts this is durch den Compiler sowie den gemeldeten Intersection-Typ. Als erledigt gilt die Aufgabe, wenn die zweite Assertion entweder auf X<string, true> eingrenzt oder den erwarteten Compile-Time-Fehler meldet und eine Regressionstestabdeckung für das Beispiel vorhanden ist.

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
Größtenteils klar
Anfängerfreundlichkeit
35/100

Neue Issues direkt in Ihr Postfach

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