在TypeScript中,如何防止在派生类上调用方法?

时间:2017-03-22 14:38:54

标签: class typescript subclass derived-class

有三个班级。

// in external library, which I don't want to modify
class ComponentBase {
    // I want calling this to be disallowed
    forceUpdate() {}
}

class ComponentBase_MyVersion extends ComponentBase {
    // I want subclasses to always call this, instead of forceUpdate()
    Update() {}
}

class MyComponent extends ComponentBase_MyVersion {
    DoSomething() {
        // I want this to be disallowed
        this.forceUpdate();

        // forcing the subclass to call this instead
        this.Update();
    }
}

如何才能完成此操作,只更改为ComponentBase_MyVersion

有没有办法“隐藏”基类成员?

或许是一种覆盖定义的方法 - 比如C#中的“new”关键字 - 让我将方法定义变为至少在尝试调用时出现警告?

3 个答案:

答案 0 :(得分:5)

OOP不允许您进行此类方法取消。您可以使用您建议的Exception在您的类上实现此功能,或使用合成:https://en.wikipedia.org/wiki/Composition_over_inheritance

示例1:

FeedListAdapter

实施例2(组合物):

class ComponentBase {
    forceUpdate() {}
}

class ComponentBase_MyVersion extends ComponentBase {
    Update() {}
    forceUpdate() {
        throw new Error("Do not call this. Call Update() instead.");
    }
}

class MyComponent extends ComponentBase_MyVersion {
    DoSomething() {
        // wil raise an exception
        this.forceUpdate();
        this.Update();
    }
}

我希望我能帮忙。

答案 1 :(得分:2)

通过使用组合delegation pattern

替换继承来实现封装

你可以在private方法上添加forceUpdate访问修饰符,这将导致所有子类无法访问forceUpdate。typescript不支持包访问修饰符,但你可以通过用继承替换继承来实现这一点。

class ComponentBase {
    forceUpdate() {
    }
}

class ComponentBase_MyVersion {
    //replace inheritance with composition.
    private component: ComponentBase;

    Update() {
        this.component.forceUpdate();
    }
}

class MyComponent extends ComponentBase_MyVersion {
    DoSomething() {
        //now subclass can't access forceUpdate method
        this.Update();
    }
}

定义一个symbol方法,外部类无法访问symbol方法。

经过几分钟的思考,我发现有一种方法可以解决这个问题,如果你不想用组合替换继承,你可以用Symbol来定义一个方法,但你必须配置tsconfig compilerOptions libs包括es2015.symbol如果你的目标是es5,因为符号是唯一的' libs.ts'无法获得该符号。

//libs.ts
let forceUpdate = Symbol("forceUpdate");
export class ComponentBase {
    [forceUpdate]() {
    }
}

export default class ComponentBase_MyVersion extends ComponentBase {
    Update() {
        this[forceUpdate]();
    }
}

//test.ts
import ComponentBase_MyVersion from "./libs";
class MyComponent extends ComponentBase_MyVersion {
    DoSomething() {
        //now subclass can't access forceUpdate method
        this.Update();
    }
}

答案 2 :(得分:0)

我发现了一种似乎有用的方法 - 也就是说,当有人试图在子类实例上调用forceUpdate()时会出现警告。

forceUpdate(_: ()=>"Do not call this. Call Update() instead.") {
    throw new Error("Do not call this. Call Update() instead.");
}

现在当我写new MyComponent().forceUpdate()时,我收到编译错误,警告消息中包含说明,告诉我改为使用Update()

编辑:显然这只有效,因为基类已经有了这个定义:

forceUpdate(callBack?: () => any): void;

如果相反基本方法最初没有参数定义(如在OP中),则上述解决方案不起作用。

但是,如果你有一个类似我的案例(那里有一个类似的可选属性,你可以缩小返回类型),它工作正常。 (不确定这种返回类型缩小是一个错误,还是有意的)