Tipos de letra mecanografiada, genéricos y clases abstractas

Experimento un comportamiento que me parece extraño.

Consideremos la siguiente muestra (pruébalo en el patio de juegos mecanografiado):

abstract class FooAbstract {
    abstract bar() {}
}

class Foo extends FooAbstract { 
    bar() { 
        return { bar: 'bar' };
    }
}

class FooMaker<FOO extends FooAbstract> {  
    constructor(public foo: FOO) {}

    bar() { 
        return this.foo.bar();
    }

    baz = () => { 
        return this.foo.bar();
    }
}

let foo = new Foo();
let result = foo.bar();

let foomaker = new FooMaker(new Foo);
let foo2 = foomaker.foo; // Type "Foo", OK
let result1 = foomaker.foo.bar(); // Type "{bar: string}", OK
let result2 = foomaker.bar(); // Type "{}", ???
let result3 = foomaker.baz(); // I've seen comments about using a lambda... Not better

result2 yresult3 se escriben como el resumenbar función ({}) Parece quethis no se resuelve como la clase concretaFoo pero como la clase abstractaFooAbstract. Mientras que el tipo defoo2 muestra que la clasefoo La propiedad se resuelve correctamente.

Que esta pasando? ¿Hago algo de manera incorrecta?

actualizar

Como una ocurrencia tardía, este caso puede reformularse así (Pruébelo en el campo de juegos de Typecript):

class Foo {
    bar() {
        return { bar: 'bar' };
    }

    getThis(): this {
        return this
    }
}

class Wrapper {  
    bar<FOO extends { bar(): {} }>(foo:FOO) {
        return foo.bar();
    }
}

let wrapper = new Wrapper();
let result = (new Foo()).bar();
let result2 = wrapper.bar(new Foo());

result tiene el tipo{bar:string}
result2 tiene el tipo{} (desde la interfaz).
wrapper.bar tiene el tipoWrapper.bar<Foo>(foo: Foo): {}

Con esta muestra, es más claro que, incluso sabiendo queFOO se escribe comoFoo, Mecanografiado usosFOO definición y no su tipo explícito comobar tipo de retorno

actualización 2

Ok, mientras peleaba con tipings, creo que subí de nivel. El concepto es, de hecho, que las tipificaciones implícitas enMecanografiado no siga ningún modelo de herencia incluso cuando se deduce un tipo. Bueno, todavía me preguntopor qué ova a cambiar, pero tendré que lidiar con "es así". Entonces, en este caso, el tipo debe ser explícito.

Encontré una manera más simple de escribir su ejemplo (pruébalo en el campo de juegos Typecript):

abstract class FooAbstract {
    abstract bar(): {}
}

class Foo extends FooAbstract { 
    bar() { 
        return { bar: 'bar' };
    }
}

class FooMaker<FOO extends FooAbstract, BAR> {  
    constructor(public foo: FOO & { bar: () => BAR } ) {       
    }

    bar():BAR { 
        return this.foo.bar() as BAR;
    }
}

let foomaker = new FooMaker(new Foo());
let result = foomaker.bar();

result obtiene el tipo{bar:string} y no hay necesidad de poner genéricos en todas partes. Las cosas en elFooMaker.constructor El tipo de parámetro podría ser más limpio al referir una interfaz con un genérico.

Respuestas a la pregunta(2)

Su respuesta a la pregunta