microsoft / microsoft/TypeScript

[3.5.0-dev.20190516] Incorrect type error for mixin

Offen
#31,426 5 Kommentare 0 Reaktionen 0 zugewiesene Personen Auf GitHub ansehen

Dieses Issue hat noch niemand übernommen.

Bug Domain: classes Needs Human Review
Vorherrschende Sprache
Go
Sterne
111k
Forks
14.3k
Ø Merge
2 T. 4 Std.
Gemergte PRs (30 T.)
132

Beschreibung

When using the mixin pattern, there are 2 main notations to define the type of the mixin entity.
The mixin pattern:

export type AnyFunction<A = any>        = (...input : any[]) => A
export type AnyConstructor<A = object>  = new (...input : any[]) => A
export type Mixin<T extends AnyFunction> = InstanceType<ReturnType<T>>

export const Box = <T extends AnyConstructor<object>>(base : T) =>
class Box extends base {
    value       : any
}

1st notation:

export type Box = Mixin<typeof Box> {}

2nd notation:

export interface Box extends Mixin<typeof Box> {}

The 1st notation can not be used for recursive definitions (#29872). Because of that we primarily use 2nd notation. It works fine in most cases, however I found a case, when it produces invalid type error. The full snippet to reproduce the problem below.

Note:

  • The typechecker correctly figures out that there's no zxc property on this, inside the observe method of Quark mixin.
  • In that method, it does not complain about the this.value usage
  • It does complain, when value is used on function argument
  • If you'll switch the Quark mixin to the 1st notation, the error will disappear

Expected behavior:

  • No type errors for the definition of test function below
export type AnyFunction<A = any>        = (...input : any[]) => A
export type AnyConstructor<A = object>  = new (...input : any[]) => A
export type Mixin<T extends AnyFunction> = InstanceType<ReturnType<T>>

export const Box = <T extends AnyConstructor<object>>(base : T) =>
class Box extends base {
    value       : any
}
export interface Box extends Mixin<typeof Box> {}

export const Observable = <T extends AnyConstructor<object>>(base : T) =>
class Observable extends base {
    observe () : Quark {
        return
    }
}
export interface Observable extends Mixin<typeof Observable> {}

export const Quark = <T extends AnyConstructor<Box & Observable>>(base : T) =>
class Quark extends base {

    observe () : Quark {
        // No error here!
        this.value
        
        // error: Error:(28, 14) TS2339: Property 'zxc' does not exist on type 'Quark'.
        this.zxc
        
        return
    }
}
export interface Quark extends Mixin<typeof Quark> {}

const test = (a : Quark) => a.value // <-- Error:(35, 28) TS2339: Property 'value' does not exist on type 'Quark'.

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, den vollständigen TypeScript-Reproducer in diesem Issue zu kompilieren und die beiden Quark-Mixin-Notationen zu vergleichen. Verfolge, wie der Checker die geerbte value-Eigenschaft innerhalb von Quark und beim Argument der Testfunktion auflöst. Fertig ist die Aufgabe, wenn die zweite Notation für a.value keinen Typfehler erzeugt, während der ungültige Zugriff auf this.zxc weiterhin einen Fehler meldet.

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
Aktiv
Klarheit
Klar beschrieben
Anfängerfreundlichkeit
52/100

Neue Issues direkt in Ihr Postfach

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