尝试在 Typescript 中覆盖和扩展子类中的方法签名

Mic*_*and 10 javascript inheritance typescript

我有一个要扩展的基类:

export class BaseClass<T extends SomeOtherClass> {
  constructor(param: ParamType) {
  }

  doSomething(param1: Param1Type): BaseClass<T> {
    // do something with param1;
    return this;
  } 
}
Run Code Online (Sandbox Code Playgroud)

我的课:

export class MyClass<T extends SomeOtherClass> extends BaseClass<T> {

  constructor(param: ParamType) {
    super(param);
  }

  doSomething(param1: Param1Type, param2: Param2Type): MyClass<T> {
    // super.doSomething(param1);
    // do something with param2;
    return this;
  }
}
Run Code Online (Sandbox Code Playgroud)

但我收到警告:

Property 'doSomething' in type 'MyClass<T>' is not assignable to the same property in base type 'BaseClass<T>'.
  Type '(param1: Param1Type, param2: Param2Type) => MyClass<T>' is not assignable to type '(param1: Param1Type) => BaseClass<T>'.
Run Code Online (Sandbox Code Playgroud)

不能在打字稿中扩展方法签名吗?如果我需要向重写的方法添加一个参数,我如何扩展 BaseClass 的功能,这是在 es6 语法中调用父方法的正确方法。我知道在 es6 之前我可以调用 BaseClass.prototype.doSomething.call(this, param1)。

Tit*_*mir 7

其他人指出的问题是,如果param2需要,它会破坏多态性:

// We should be able to do this assignment 
let baseRef: BaseClass<SomeOtherClass> = new MyClass<SomeOtherClass>(""); 
baseRef.doSomething("") // param2 is not required by the base class so MyClass will not receive it even though it NEEDS it
Run Code Online (Sandbox Code Playgroud)

一种解决方案是将第二个参数设为可选,因此该调用baseRef.doSomething("")对于派生类型也有效:

export class MyClass<T extends SomeOtherClass> extends BaseClass<T> {

    constructor(param: string) {
        super(param);
    }

    doSomething(param1: string, param2?: string): MyClass<T> {
        super.doSomething(param1);
        return this;
    }
}
Run Code Online (Sandbox Code Playgroud)

第二种解决方案,如果我们只想在类之间共享代码,则let baseRef: BaseClass<SomeOtherClass> = new MyClass<SomeOtherClass>("");通过不真正继承BaseClass而是继承排除该doSomething方法的类来禁止赋值:

type PartialBaseClass = new <T> (param: string)  => { [P in Exclude<keyof BaseClass<T>, 'doSomething'>] : BaseClass<T>[P] }
const PartialBaseClass:PartialBaseClass = BaseClass

export class MyClass<T extends SomeOtherClass> extends PartialBaseClass<T> {

    constructor(param: string) {
        super(param);
    }

    doSomething(param1: string, param2: string): MyClass<T> {
        BaseClass.prototype.doSomething.call(this, param1);
        return this;
    }
}
// This is now invalid ! 
let baseRef: BaseClass<SomeOtherClass> = new MyClass<SomeOtherClass>("")    ;
Run Code Online (Sandbox Code Playgroud)