Search code examples
typescriptabstract-class

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();
    }
}

Solution

  • 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