Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Abstract property in class cannot be accessed in the constructor

In the following example, I'm getting the TypeScript error Abstract property 'name' in class 'Minigame' cannot be accessed in the constructor.

I'm struggling to think how I could implement this. I can't pass the concrete class' name into the super() call because I can't access properties of the object before that call, and I can't make the properties static because the abstract class can't enforce that.

How should this be organized to guarantee every Minigame instantiates an Explanation object, which requires the concrete class' name property? Is making the name static (and removing the abstract requirement) really my best option to keep it simple?

abstract class Minigame {
    abstract name: string;
    explanation: Explanation;

    constructor() {
        this.explanation = new Explanation(this.name);
    }
}

class SomeGame extends Minigame {
    name = "Some Game's Name";

    constructor() {
        super();
    }
}
like image 961
MattTreichel Avatar asked Jan 20 '19 02:01

MattTreichel


2 Answers

It's a little ugly for a string, but you could do:

abstract class Minigame {
    abstract GetName(): string;
    explanation: Explanation;

    constructor() {
        this.explanation = new Explanation(this.GetName());
    }
}

class SomeGame extends Minigame {
    GetName(): string {
        return "Some Game's Name";
    }

    constructor() {
        super();
    }
}
like image 110
Tam Coton Avatar answered Nov 15 '22 08:11

Tam Coton


Here another solution based on Tom Coton which does not forces to implement the getName method.

Just moving the name in abstract class as constructor argument.

class Explanation {
    name: string;
    constructor(name: string) {
        this.name = name;
    }
}

abstract class Minigame {
    explanation: Explanation;  
    name: string;
    constructor(name) { 
        this.name = name;
        this.explanation = new Explanation(this.name);
    }
} 

class SomeGame extends Minigame {
    constructor() {
       super('some game')
    }

}

const game = new SomeGame();

console.log({ game: game })

you can check here by clicking in "Run"

https://www.typescriptlang.org/play?#code/MYGwhgzhAECiAeAHcA7MAXAlgexdA3gLABQ0Z0aAtgKYBc0E6ATpigOYDcJ50wujTAK7B02JgAoqdBs1ZsAlAW49y6ABaYIAOinQAvBTA0upcgF8SF4iTAAjAWBG9wUaAFlWmNkepLTZaiRUDBwUegRkMDQsXA5yZTIpegE5Ex4+FAFhUQkkmRZ2RXxoBJV1TR0ffUNjUp5y7UDI6NDqlGoAdzggqJDccQbKmnk080sS62JQSBgAZWwaAHEqwPRqFAATGA8ULyri0oyskTFxIrryCEFEagkAcggF328aO-lSqysSI-RoF98DO0uvMlj4ziZvvxsCBqFoQNg2OJiv96P9oGZ5EA

In case of needing to re-create the Explanation every time the name is set you could use setter & getters in addition:

class Explanation {
    name: string;
    constructor(name: string) {
        this.name = name;
    }
}

abstract class Minigame {
    explanation?: Explanation;   
    private _name?: string;

    set name(name: string | undefined) {
        this._name = name;
        if(name) {
         this.explanation =  new Explanation(name);
        }
    }

    get name(): string | undefined{
        return this._name;
    }

    constructor(name?: string) {
        this.name = name;
    }
} 

class SomeGame extends Minigame { 

    constructor() {
        super('some game');
    }

}

const game = new SomeGame();

console.log({ game: game })

https://www.typescriptlang.org/play?#code/MYGwhgzhAECiAeAHcA7MAXAlgexdA3gLABQ0Z0aAtgKYBc0E6ATpigOYDcJ50wujTAK7B02JgAoqdBs1ZsAlAW49y6ABaYIAOinQAvBTA0upcgF8SF4iTAAjAWBG9wUaAFlWmNkepLTZaiRUDBwUAH56BGQwNCxcDnJlMkQWADcMXwB9KQiZFnYTJIZqdEMaSR96ATloAB9oQRQAE2oAM1ZqJsUifxV1TS1sn30y6hMVckxWippuor6NbUDo2NCRimoAdzggmJDcGep5cYnoKx4rIrYS0fF5Ktl2Oobmto6mntPoJhLBJjx+tohsYipdenwUAJhKIJDkHvkFH4voCdMMDFITmQrGZoCQSKBIDAAMrYGgAcWGgXQ1GaMA8KC8w3wuOs4P4zGhYjuSNOEEEiGoEgA5BBSb5vDQhcdQXjiGCIYxoBLfOittASeSfHdCsQFdgQNQtCBsGxxMzlfRlWd5EA

like image 40
Angel Fraga Parodi Avatar answered Nov 15 '22 06:11

Angel Fraga Parodi