web-dev-qa-db-fra.com

TypeScript - comment hériter d'une classe et remplacer une méthode lambda

J'ai une classe héritée et j'ai besoin que le parent ait une méthode virtuelle, qui est remplacée par la classe enfant. Cette méthode est appelée à partir du constructeur de base et nécessite un accès aux propriétés d'instance. Elle doit donc être une fonction lambda. "This" est donc "_this". Le problème est que remplacer une méthode lambda ne fonctionne pas pour moi, contrairement à une méthode non lambda. Est-ce possible? Sinon, j'aimerais comprendre pourquoi.

En outre, "ceci" sera-t-il toujours identique à "_this" lorsque la méthode n'est appelée qu'à partir du constructeur?

class Base {
    protected prop = null;
    constructor() {
        this.init();
        this.initLambda();
    }
    init() {
        console.log("Base init");
    }
    initLambda = () => {
        console.log("Base initLambda");
    }
}
class Derived extends Base {
    constructor() {
        super();
    }
    init() {
        console.log("Derived init");
    }
    initLambda = () => {
        //let x = this.prop;
        console.log("Derived initLambda");
    }
}

Sortie:
Init dérivé
Base initLambda

8
user210757

Eh bien, vous ne pouvez pas avoir ça.
Il y a un problème qui a été ouvert mais il a été fermé comme "à dessein".

Vous devriez utiliser des méthodes régulières:

class Base {
    protected prop = null;

    constructor() {
        this.init();
        this.initLambda();
    }

    init() {
        console.log("Base init");
    }

    initLambda() {
        console.log("Base initLambda");
    }
}

class Derived extends Base {
    constructor() {
        super();
    }

    init() {
        console.log("Derived init");
    }

    initLambda() {
        console.log("Derived initLambda");
    }
}

Et puis ça va marcher.

En ce qui concerne la bonne this, vous pouvez toujours passer un appel à la méthode sous forme de fonction de flèche:

doit() {
    setTimeout(() => this.init(), 1);
}

Ou utilisez le Function.prototype.bind function:

setTimeout(this.init.bind(this));

De plus, le _this produit par le compilateur TypeScript est simplement un hack permettant de polyfiler les fonctions de flèche pour ES5, mais si vous modifiez la cible en ES6, elle ne l'utilisera pas.


Modifier:

Vous pouvez enregistrer les méthodes liées en tant que membres:

class Base {
    ...
    public boundInit: () => void;

    constructor() {
        ...
        this.boundInit = this.initLambda.bind(this);
        setTimeout(this.boundInit, 500);
    }

...

Avec cela, quand je fais new Derived() c'est ce que je reçois:

Dérivée init
InitLambda dérivé // après 200 millis

12
Nitzan Tomer

Le problème est que votre lambda est une propriété.

Lorsque compilé en javascript, la Baseclass devient 

var Base = (function () {
    function Base() {
        this.prop = null;
        this.initLambda = function () {
            console.log("Base initLambda");
        };
        this.init();
        this.initLambda();
    }
    Base.prototype.init = function () {
        console.log("Base init");
    };
    return Base;
}());

Comme vous pouvez le constater, initLambda est défini à l'intérieur du constructeur de Base, il est donc impossible de remplacer ce paramètre.

L'appel de super() appelle le constructeur Base qui définit le this.initLambda avec le code dans Base et l'exécute. D'où votre résultat.

Vue sur terrain de jeu

2
Bruno Grieder