Home > Software engineering >  Property x in type ClassB is not assignable to the same property in base type ClassA
Property x in type ClassB is not assignable to the same property in base type ClassA

Time:03-21

I work with the following Typescript classes:

  1. I have an abstract class

    export abstract class MyAbstractClass {
    .....
    }
    
  2. Class A wich implements the methods of the abstract class

    export ClassA extends MyAbstractClass {
    
    readonly MY_FIRST_CONTS = 'blaa';
    readonly MY_SECOND_CONTS = 'blaablaaa';
    
    ....
    }
    
  3. class B wich extends class A and I want to override the MY_FIRST_CONTS value. No other implementation is set

    export ClassB extends ClassA {
    
    readonly MY_FIRST_CONTS = 'other blaa';
    readonly MY_SECOND_CONTS = 'other blaablaaa';
    
    ....
    }
    

I contantly get the following error at the line of MY_FIRST_CONST in ClassB:

   Property 'MY_FIRST_CONST' in type 'ClassB' is not assignable to the same property in base type 'ClassA'.

Type '"other blaa"' is not assignable to type '"blaa"'.

I do not get why this error comes and even less why it does not happen with MY_SECOND_CONST.

Any ideas? Thanks a lot!

CodePudding user response:

You have a design problem. The technical problem comes from the fact that you are overriding a readonly attribute in a subclass, which does not make sense.

Either you want subclasses to be able to change the value, then it should not be readonly. Or you don't want subclasses to be able to change the value, then you cannot declare a different value in the subclass.

But, you might also want subclasses to be able to define a value that cannot be changed after instantiation. This can be done either with an appropriate constructor or with getters :

With a constructor :

export class ClassA extends MyAbstractClass {

  readonly foo;

  constructor(foo = 'foo') {
    super();
    this.foo = foo;
  }
}

export class B extends ClassA {

  constructor() {
    super('bar')
  }
}

With getters :

export class ClassA extends MyAbstractClass {
  get foo() {
    return 'foo';
  }
}

export class B extends ClassA {
  get foo() {
    return 'bar';
  }
}

CodePudding user response:

In order to answer this question we need to see how the compiler traduce all this in JS:

"use strict";
class AbstractClass {
}
class ClassA extends AbstractClass {
    constructor() {
        super(...arguments);
        this.MY_FIRST_CONTS = 'blaa';
        this.MY_SECOND_CONTS = 'blaablaaa';
    }
}
class ClassB extends ClassA {
    constructor() {
        super(...arguments);
        this.MY_FIRST_CONTS = 'other blaa';
        this.MY_SECOND_CONTS = 'other blaablaaa';
    }
}

This is easy to say, the same variable is declared twice, and Typescript give you an error because you declared the variables in ClassA as readonly.

If you still need the two variables both in ClassA and ClassB you can declared the variables in ClassA as stricty private.

export ClassA extends MyAbstractClass {

#MY_FIRST_CONTS = 'blaa';
#MY_SECOND_CONTS = 'blaablaaa';

....
}

Now you might think to access the variables in ClassA with a get, but this will raise another error for the same reason.

export class ClassA extends AbstractClass {
    #MY_FIRST_CONTS = 'blaa';
    #MY_SECOND_CONTS = 'blaablaaa';

    get MY_FIRST_CONTS() { return this.#MY_FIRST_CONTS}
    get MY_SECOND_CONTS() { return this.#MY_SECOND_CONTS}
}

export class ClassB extends ClassA {
    //'MY_FIRST_CONTS' is defined as an accessor in class 'ClassA', but is overridden here in 'ClassB' as an instance property.
    readonly MY_FIRST_CONTS = 'other blaa';
    //'MY_SECOND_CONTS' is defined as an accessor in class 'ClassA', but is overridden here in 'ClassB' as an instance property.
    readonly MY_SECOND_CONTS = 'other blaablaaa';
}

So, to make this works, you have to wrap the variables in a get method, and then override the get methods in ClassB:

export abstract class AbstractClass {

}

export class ClassA extends AbstractClass {
    #MY_FIRST_CONTS = 'blaa';
    #MY_SECOND_CONTS = 'blaablaaa';

    get MY_FIRST_CONTS() { return this.#MY_FIRST_CONTS}
    get MY_SECOND_CONTS() { return this.#MY_SECOND_CONTS}
}

export class ClassB extends ClassA {
    #MY_FIRST_CONTS = 'other blaa';
    #MY_SECOND_CONTS = 'other blaablaaa';

    override get MY_FIRST_CONTS() {return this.#MY_FIRST_CONTS}
    override get MY_SECOND_CONTS() {return this.#MY_SECOND_CONTS}
}

CodePudding user response:

depending on your Typescript version, did you try to specify that it is override ?

https://www.typescriptlang.org/docs/handbook/release-notes/typescript-4-3.html

  export class ClassB extends ClassA {

    override MY_FIRST_CONTS = 'blaa';
    override MY_SECOND_CONTS = 'blaablaaa';
  
    }
  • Related