How to fix metod overloding issue with Angular 4, with different data type?

问题: 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.

  • 发表于 2018-12-28 19:15
  • 阅读 ( 203 )
  • 分类:网络文章

条评论

请先 登录 后评论
不写代码的码农
小编

篇文章

作家榜 »

  1. 小编 文章
返回顶部
部分文章转自于网络,若有侵权请联系我们删除