簡體   English   中英

在 TypeScript 中,如何防止在派生類上調用方法?

[英]In TypeScript, how to prevent a method from being called on 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”關鍵字一樣——讓我修改方法定義以至少在嘗試調用它時出現警告?

OOP 不允許您執行這種方法取消。 您可以使用您建議的 Exception 在您的班級上實現此功能,或者使用組合: https ://en.wikipedia.org/wiki/Composition_over_inheritance

示例 1:

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();
    }
}

例2(組成):

class ComponentBase {
    forceUpdate() {}
}

class ComponentBase_MyVersion {
    private _component: ComponentBase = ...;
    Update() {}
    // expose _component desired members ...
}

class MyComponent extends ComponentBase_MyVersion {
    DoSomething() {
        // compilation error
        this.forceUpdate();
        this.Update();
    }
}

我希望我有所幫助。

通過用組合委托模式替換繼承來封裝實現

您可以通過在forceUpdate方法上添加private訪問修飾符來做到這一點。 這將導致所有子類無法訪問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來定義方法。 如果您的目標是es5 ,則必須配置tsconfig.json compilerOptions.lib以包含es2015.symbol 因為每個symbol都是唯一的,任何外部模塊都無法獲取符號並訪問該方法。

// 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 the forceUpdate method.
        this.Update();
    }
}

我找到了一種似乎有效的方法——也就是說,當有人試圖在子類實例上調用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 中),則上述解決方案不起作用。

但是,如果您有像我這樣的案例(其中有一個類似的可選屬性,您可以縮小其返回類型),它可以正常工作。 (不確定這種返回類型縮小是錯誤還是有意為之)

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM