访问扩展类中的覆盖受保护成员

时间:2018-03-08 14:38:39

标签: typescript

我们假设我有一个Base类和一个Test类,它来自BaseBase类有一个受保护的成员,让我们说它是一个存储字符串字典的对象。我希望在Test类中覆盖该字典,但不知何故,它不能按预期工作(至少在我的生产代码中,以及我在JS Bin上测试时):

type ConstantsDict = { [key: string]: string }

abstract class Base {

    protected readonly _constants: ConstantsDict = {
        FOO: 'bar'
    }

    protected get _magicStringFoo(): string {
        return `Base: ${this._constants.FOO}`;
    }

    constructor() {
        // The magic constant FOO is incorrect when invoked in Test
        alert(this._magicStringFoo);
    }
}

class Test extends Base {
    // Overwrite inherited  member
    protected readonly _constants = {
        FOO: 'lorem ipsum dolor sit amet'
    }

    // Overwrite inherited getter
    protected get _magicStringFoo(): string {
        return `Test: ${this._constants.FOO}`;
    }

    // Let's give Test it's own getter for the same magic constant
    private get _magicStringFooPrivate(): string {
        return `Test: ${this._constants.FOO}`;
    }

    constructor() {
        super();

        // The magic constant FOO is correct over here
        alert(`Local magic constant FOO is: ${this._magicStringFooPrivate}`)
    }
}

new Test();

代码会提醒Test: bar而不是Test: lorem ipsum dolor sit amet。好消息是从Base类继承的受保护的getter正在Test中被覆盖,但不知怎的,this引用仍指向不正确的类。

1 个答案:

答案 0 :(得分:1)

这是由构造函数如何交互引起的排序问题。

以下是基于代码的构造函数(为了便于使用而删除了所有其他代码)。

我在实例化新的Test

时调用了每行的注释时间
// 3
function Base() { 
    // 4
    this._constants = { 
        // 5
        FOO: 'bar' 
    // 6
    }; 
    // 7 (at this point, FOO is 'bar')
    alert(this._magicStringFoo);
}

// 1
function Test() { 
    // 2
    var _this = _super.call(this) || this; // <-- GO TO SUPER CLASS CONSTRUCTOR
    // 8
    _this._constants = {
        // 9
        FOO: 'lorem ipsum dolor sit amet'
    // 10
    };
    // 11
    alert("Local magic constant FOO is: " + _this._magicStringFooPrivate);
    //12
    return _this;
}

你可以在这里看到为什么子类似乎有错误的值 - 它只是没有机会在那时覆盖基类值。

修复

我建议的修复方法是将值传递给超类构造函数。

这是一个简单的版本:

type ConstantsDict = { [key: string]: string }

abstract class Base {
    constructor(protected magicStringFoo: string) {
        // The magic constant FOO is incorrect when invoked in Test
        alert(this.magicStringFoo);
    }
}

class Test extends Base {
    constructor() {
        super('Test: lorem ipsum dolor sit amet');
    }
}

new Test();

我已将测试字符串传递给那里,但您可以传递FOO常量或任何您需要的值。这解决了任何订购问题。