Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

TS2611: 'foo' is defined as a property in class 'A', but is overridden here in 'B' as an accessor

I am facing a Typescript compilation error in my Angular app. Following is the sample code and error message.

Would you please guide me to suppress this error. I think this code is correct as per the Javascript.

- error TS2611: 'foo' is defined as a property in class 'A', but is overridden here in 'B' as an accessor.
export class A {
  foo: string;
}

export class B extends A {
  f1;
  set foo(name) {
    this.f1 = name;
  }
  get foo() {
    return this.f1;
  }
}

Editor's note: in the comments it emerged that both classes A and B are in third-party libraries.

like image 946
PARAMANANDA PRADHAN Avatar asked Sep 05 '20 05:09

PARAMANANDA PRADHAN


3 Answers

The error message is correct as there is a subtle bug here. When you define a property in a parent class, the property is created automatically for every one of its sub-classes.

So, in the code you wrote, had you not written for class B: set/get foo(name) { ... } the class would have had the foo property anyway since the property is declared in B's parent class - A.

In your code you're actually clobbering the foo property declared in A with the accessor declarations.

If you want to require all sub-classes of A to declare their own foo property (similar to an interface), then try:

export class A {
  abstract foo: string;
}
like image 154
Scott Steinbach Avatar answered Oct 17 '22 22:10

Scott Steinbach


Another way to do this is to create an abstract class that you can use to extend your sub-classes. I use an interface then an abstract then extend it in my final class like so with the accessors (get/set).

In the interface you will define your properties. However, if you're going to use accessors (get/set) you need to create an abstract. I would do this only on data type classes where you store and retrieve data against a class.

The example below can be found here Typescript playground example with interface, abstract, extend

interface IQuote {

    qty: number,
    rate: number | string,
    total ? : number | string
}

abstract class AQuote implements IQuote {
  abstract set qty(x: number);
  abstract get qty(): number;
  abstract set rate(x: number | string);
  abstract get rate(): number | string;
  abstract set total(x: number | string);
  abstract get total(): number | string


  protected abstract updateTotal(): void
  abstract getTotalNum(): number


}

class quote extends AQuote {

  constructor(obj: IQuote) {
    super()
    this.qty = obj.qty
    this.rate = obj.rate
  }

  set qty(v: number) {
    this._qty = v;
    this.updateTotal()
  }

  get qty() {
    return this._qty;

  }

  set rate(v: number | string) {
    this._rate = Number(v);
    this.updateTotal()
  }

  get rate() {
    return new Intl.NumberFormat('en-GB', {
      style: 'currency',
      currency: 'GBP'
    }).format(Number(this._rate))
  }

  set total(v: number | string) {
    this._total = Number(v);
  }

  get total(): number | string {
    return new Intl.NumberFormat('en-GB', {
      style: 'currency',
      currency: 'GBP'
    }).format(Number(this._total))
  }

  getTotalNum() {
    return Number(this._total)
  }

  protected updateTotal() {
    this.total = Number(this._rate) * Number(this._qty)
  }

  private _qty: number = 1;
  private _rate: number | string = 1;
  private _total ? : number | string = (Number(this._rate) * this._qty);

}



class QuoteArray extends Array < quote > {

  getTotals(): number {
    let totalFigure: number = 0
    this.forEach(o => {
      totalFigure = totalFigure + o.getTotalNum()
    });
    return totalFigure
  }

}

let arry: QuoteArray = new QuoteArray();

arry.push(new quote({
  qty: 2,
  rate: 5
}))

arry.push(new quote({
  qty: 3,
  rate: 5
}))
arry.push(new quote({
  qty: 3,
  rate: 5
}))
arry.push(new quote({
  qty: 3,
  rate: 5
}))
arry.push(new quote({
  qty: 3,
  rate: 5
}))




console.log(arry);


console.log(arry.getTotals())

The example above creates an Array of quotes that I can manipulate like an array but I have also extended the Array type to give me method called getTotals() so that it prints out a formatted currency.

like image 3
B.Ramburn Avatar answered Oct 17 '22 22:10

B.Ramburn


It is usual behavior in programming languages, when you inherit from parent you can't use same variable/function/accessor names until you specify that new one override old one, but always this must be the same type. So in your example we have variable in parent and accessor in child. You can do this change:

class A {
  _foo: string = "";
  set foo(name) {
    this._foo = name;
  }
  get foo() {
    return this._foo;
  }
}

export class B extends A {
  f1: any;
  set foo(name) {
    this.f1 = name;
  }
  get foo() {
    return this.f1;
  }
}

I believe there is some way to omit type limitations (if you have to) but I don't know how and I think that is not good way (program should be clear for reader).

like image 1
Leszek Mazur Avatar answered Oct 17 '22 21:10

Leszek Mazur