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.
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;
}
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.
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).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With