microsoft / microsoft/TypeScript

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

Abierto
#31,426 5 comentarios 0 reacciones 0 asignados Ver en GitHub

Nadie ha tomado este issue todavía.

Bug Domain: classes Needs Human Review
Lenguaje dominante
Go
Estrellas
111k
Forks
14.4k
Merge medio
1 d 19 h
PR fusionados (30 d)
117

Descripción

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'.

Guía de contribución

Abrir la guía de contribución

Primeros pasos

  1. Lee el issue completo y luego la guía de contribución del proyecto.
  2. Comenta en el issue que vas a ocuparte — evita que dos personas hagan lo mismo.
  3. Haz un fork del repositorio y trabaja en una rama.
  4. Abre un pull request que haga referencia al número del issue.

Línea de trabajo

Comienza compilando el reproducer completo de TypeScript incluido en este issue y compara las dos notaciones de mixin de Quark. Sigue cómo el checker resuelve la propiedad value heredada dentro de Quark y en el argumento de la función de prueba. Se considera terminado cuando la segunda notación no produce ningún error de tipo para a.value, mientras que el acceso no válido a this.zxc sigue informando de un error.

Escrito por el modelo de indexación a partir del texto del issue.

Evaluación

Stack tecnológico
typescript
Área
compilers
Tipo de issue
Error
Dificultad
4/5
Tiempo estimado
3-5 días
Estado de actividad
Activo
Claridad
Bien especificado
Aptitud para principiantes
52/100

Recibe los nuevos issues en tu correo

Un resumen breve de issues de GitHub para principiantes.