Ivan V.
Ivan V.

Reputation: 8091

Child class cannot use subtype property in place of the parent class property

Okay strange title, not sure how else to put it. So this is the problem. I was under the impression that if I pass in the subtype of the parent constructor property, to the child constructor property everything will work. However, that is not the case. If I try to use the subtype method on the child property I get an error.

interface IDataMaper{
    save():void
}

interface IReactiveDataMapper extends IDataMaper{
    saveReactive():void
}


class A {
    constructor(protected mapper: IDataMaper) {}
}

class B extends A {

    constructor(mapper: IReactiveDataMapper) {
        super(mapper)//no errror here
        // this.mapper.saveReactive() //error
    }
}   

Typescript Playground

Upvotes: 1

Views: 220

Answers (2)

kaya3
kaya3

Reputation: 51093

Lukas's answer gives a good explanation of why this error occurs; the type of this.mapper is IDataMapper, not the more specific type IReactiveDataMapper.

As an alternative solution which doesn't require changing the type of the field or declaring a new field with a different type, you can call the method on the parameter mapper, which references the same object as this.mapper but has the more specific type:

class B extends A {
    constructor(mapper: IReactiveDataMapper) {
        super(mapper);
        mapper.saveReactive(); // instead of this.mapper
    }
}

This option may be simpler if you only need the more specific type in the constructor, as in your example. If you need this.mapper to have the more specific type in other methods in the subclass, then Lukas's answer is the best way.

Upvotes: 0

Lukas Bach
Lukas Bach

Reputation: 3909

The problem is that you are accessing the mapper instance from the this context. Note the protected mapper: IDataMapper in the constructor of class A. By prepending the keyword protected there, you enforce that the class A will have a protected member called mapper of the type IDataMapper. In the constructor of B, you do not have the keyword protected, meaning that the protected member mapper of B's this-context is not overwritten, and the IDataMapper-property stored by A is used. Add a protected-prefix to the variable in B's constructor to have it overwrite the member and you will not experience the error.

interface IDataMaper{
    save():void
}

interface IReactiveDataMapper extends IDataMaper{
    saveReactive():void
}


class A {
    constructor(protected mapper: IDataMaper) {}
}

class B extends A {

    constructor(protected mapper: IReactiveDataMapper) {
        super(mapper);
        this.mapper.saveReactive();
    }
}   

Playground Link

Upvotes: 1

Related Questions