在扩展类中使用不同参数类型覆盖方法 - Typescript

时间:2018-06-06 20:57:39

标签: typescript inheritance class-method

我想覆盖一个方法并将不同的参数类型传递给它:

class Base {
    public myMethod(myString: string): undefined {
        return;
    }
}

class Child extends Base {
    public myMethod(myNumber: number): undefined {
        return super.myMethod(String(myNumber));
    }
}

然而,这会产生打字稿错误:

  

财产' myMethod'在类型'儿童'不能分配给它   基本类型的基础'基地'。输入'(myNumber:number)=>未定义'   不能分配给类型'(myString:string)=>未定义&#39 ;.       参数类型' myNumber'和' myString'是不相容的。         输入' string'不能分配类型'数字'。

有没有办法在不创建打字稿错误的情况下执行此操作?

3 个答案:

答案 0 :(得分:4)

没有办法做到这一点*。在TypeScript中,inheritance implies subtyping,因此您不能从基类继承而不是它的有效子类型。

<子> *技术上并非如此,但我不会提及它们,因为它们是您不应该做的严重黑客攻击。

答案 1 :(得分:2)

正如其他人所说,这不是一个好主意,因为你打破Liskov替代。

您可以轻松完成的工作是提供同时包含stringnumber的覆盖。这允许您的类仍然可以在预期的基类的任何地方使用。

class Base {
     public myMethod(myString: string): undefined {
         return;
     }
 }

class Child extends Base {
    public myMethod(myNumberOrString: number | string): undefined {
        if (typeof myNumberOrString === 'number') {
            return super.myMethod(String(myNumberOrString));
        } else {
            return super.myMethod(myNumberOrString);
        }
    }
}

答案 2 :(得分:1)

至少对于使用中间类的TypeScript v 4.02,似乎有一种方法,甚至对于返回类型也是如此。

但这打破了Liskov替换原则,因为它更改了返回类型,并且无法处理参数为字符串的情况。

因此,仅出于知识的考虑而值得一提,但是在代码审查中,我不会接受这种攻击,因为子类应该能够在不破坏功能的情况下替换基类。

class Base {
    public myMethod(myString: string): string {
        return myString + myString;
    }
}

// weaken
// inspired by comment here: https://github.com/microsoft/TypeScript/issues/3402#issuecomment-385975990
class Interim extends Base {
    public myMethod(x: any): any { return super.myMethod(x); }
}

class Child extends Interim {
    public myMethod(myNumber: number): number {
        return myNumber * myNumber;
    }
}

// we can have a helper/utility for this
function weaken(klass: { new(...args: any[]): any; }, key: string) {
    return class extends klass {
        [key](...args: any[]) { super[key](...args); }
    }
}


class ChildOther extends weaken(Base, 'myMethod') {
    public myMethod(myNumber: number): number {
        return myNumber * myNumber;
    }
}

console.log((new Child()) instanceof Base); // true
console.log((new ChildOther()) instanceof Base); // true
console.log(new Base().myMethod('str')); // strstr
console.log(new Child().myMethod(3)); // 9
console.log(new ChildOther().myMethod(3)); // 9