Tipografia datilografada, genéricos e classes abstratas

Eu experimento um comportamento que me parece estranho.

Vamos considerar a seguinte amostra (testá-lo no playground Typcript):

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 eresult3 são digitados como o resumobar função ({}) Parece quethis não é resolvido como a classe concretaFoo mas como a classe abstrataFooAbstract. Considerando que o tipo defoo2 mostra que a classefoo A propriedade foi resolvida corretamente.

O que está acontecendo? Faço algo da maneira errada?

atualizar

Como uma reflexão tardia, esse caso pode ser reformulado dessa maneira (Teste-o no playground Typcript):

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 tem o tipo{bar:string}
result2 tem o tipo{} (a partir da interface).
wrapper.bar tem o tipoWrapper.bar<Foo>(foo: Foo): {}

Com esta amostra, fica mais claro que, mesmo sabendo queFOO é digitado comoFoo, Texto datilografado usaFOO definição e não seu tipo explícito comobar tipo de retorno.

atualização 2

Ok, enquanto lutava com digitações, acho que subi de nível. O conceito é que tipificações implícitas emTexto datilografado não siga nenhum modelo de herança, mesmo quando um tipo é deduzido. Bem, eu ainda me perguntoporque ouisso vai mudar, mas vou ter que lidar com "é assim". Portanto, neste caso, o tipo deve ser explícito.

Encontrei uma maneira mais simples de escrever seu exemplo (tente no playground Typcript):

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 obtém o tipo{bar:string} e não há necessidade de colocar genéricos em todos os lugares. As coisas noFooMaker.constructor O tipo de parâmetro pode ficar mais limpo consultando uma interface com um genérico.

questionAnswers(2)

yourAnswerToTheQuestion