问题:
This is my demo code:
class First {
x: string;
y: string;
constructor()
{
}
setValue(x: string, y: string): void {...
可以将文章内容翻译成中文,广告屏蔽插件会导致该功能失效:
问题:
This is my demo code:
class First {
x: string;
y: string;
constructor()
{
}
setValue(x: string, y: string): void {
this.x = x;
this.y = y;
console.log("setValue In A value of x and y:", this.x, this.y);
}
getValue(): void {
console.log("getValue In A value of x and y:", this.x, this.y);
}
}
class Second extends First {
x: string = '5';
z: number;
constructor() {
super();
}
setValue(z: number, y: string) {
this.z = z;
this.y = y;
return super.setValue(this.x, this.y);
}
}
I have two class, First and Second. But in Class Second I am getting below error
Property 'setValue' in type 'Second' is not assignable to the same property in base type 'First'. Type '(z: number, y: string) => void' is not assignable to type '(x: string, y: string) => void'. Types of parameters 'z' and 'x' are incompatible. Type 'string' is not assignable to type 'number'
I tried with some possible solutions by giving type as 'any' in the Class first method also tried with another patch by giving union type in Class second as z: string | number
But both solution is patchwork towards the problem but not able to solve the original issue as we can pass string or number but actually, it accepts only string. Clearing more if suppose that method only accept one argument then any of above solution won't work.
I hope it's clear with my problem.
回答1:
The problem is that what you are trying to do breaks OOP principles. Assuming the overload you want would be allowed consider the flowing code:
let f: First = new Second() // Assign a derived class to a base type reference
f.setValue("Not a number", "y") // Second is getting a string insead of a number
In the code above Second
will receive as the first argument a string
instead of a number since we are invoking through a base class reference.
One solution is to keep both the original signature and add the signature with the number and make sure both work as expected:
class First {
x: string;
y: string;
constructor()
{
}
setValue(x: string, y: string): void {
this.x = x;
this.y = y;
console.log("setValue In A value of x and y:", this.x, this.y);
}
getValue(): void {
console.log("getValue In A value of x and y:", this.x, this.y);
}
}
class Second extends First {
x: string = '5';
z: number;
constructor() {
super();
}
setValue(x: string, y: string)
setValue(z: number, y: string)
setValue(xz: string | number, y: string) {
if (typeof xz == 'number') {
this.z = xz; // xz is number so we got called with z
this.y = y;
return super.setValue(this.x, this.y);
} else {
// xz is string so we got called with x
return super.setValue(xz, y);
}
}
}
let f: First = new Second() // Assign a derived class to a base type reference
f.setValue("Not a number", "y") // Works as expected now
Generally when you are deriving classes you can add to the public signature of the class but you can't take from it as that would break the tenant of OOP that you can safely assign a derived class to a base class reference.
Note Typescript is very flexible with it's types and you can do some type surgery to remove the setValue
from First
in order to have a higher degree of freedom in Second
. I can provide such a solution, but I highly recommend against it.