23

How to correctly define private abstract methods in TypeScript?

Here is a simple code:

abstract class Fruit {
    name: string;
    constructor (name: string) {
        this.name = name
    }
    abstract private hiFrase (): string;
}

class Apple extends Fruit {
    isCitrus: boolean;
    constructor(name: string, isCitrus: boolean) {
        super(name);
        this.isCitrus = isCitrus;
    }

    private hiFrase(): string {
        return "Hi! I\'m an aplle and my name is " + this.name + " and I'm " + (isCitrus ? "" : " not ") + "citrus";
    }

    public sayHi() {
        alert(this.hiFrase())
    }
}

This code does not work. How to fix it?

Zurab
  • 1,411
  • 3
  • 17
  • 39
  • Possible duplicate of http://stackoverflow.com/questions/13333489/declaring-abstract-method-in-typescript – Muhammad Ramzan Dec 02 '16 at 11:49
  • 5
    `private` == only accessible within the very same class. `abstract` == not implemented within this class but in some inheriting class. There's a clash of definitions here. – deceze Dec 02 '16 at 11:51
  • 7
    You want `protected abstract`, not `private abstract`. – Matthew Layton Dec 02 '16 at 11:54
  • +deceze, Does it mean that I have to define `hiFrase()` method in each derived class (`Pear`, `Orange`, etc.) ? – Zurab Dec 02 '16 at 11:57
  • +series0ne, I would prefer it to be a private method, but if I can't protected is acceptable decision too. Thanks – Zurab Dec 02 '16 at 12:04
  • Any class that directly extends the `abstract` class needs to implement the `abstract` method, yes. That's what that is all about. – deceze Dec 02 '16 at 12:12
  • @deceze Actually, since TS is a little bit higgledy-piggledy about privates and is forced to make them part of the public contracts, it would make some sense, in TS-world, to allow private abstract definitions. – Alex Dec 02 '16 at 12:55
  • @Zurab-D `private` and `protected` aren't that dissimilar, `protected` is still hidden from the public facing interface, but it CAN be overridden in derived classes - that's what it's for! – Matthew Layton Dec 02 '16 at 13:24

1 Answers1

24

Quick aside, isCitrus should be this.isCitrus. On with the main show...

Abstract methods must be visible to sub-classes, because you are requiring the sub-class to implement the method.

abstract class Fruit {
    name: string;
    constructor (name: string) {
        this.name = name
    }
    protected abstract hiFrase(): string;
}

class Apple extends Fruit {
    isCitrus: boolean;
    constructor(name: string, isCitrus: boolean) {
        super(name);
        this.isCitrus = isCitrus;
    }

    protected hiFrase(): string {
        return "Hi! I\'m an aplle and my name is " + this.name + " and I'm " + (this.isCitrus ? "" : " not ") + "citrus";
    }

    public sayHi() {
        alert(this.hiFrase())
    }
}

If you want the method to be truly private, don't declare it on the base class.

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

class Apple extends Fruit {
    isCitrus: boolean;
    constructor(name: string, isCitrus: boolean) {
        super(name);
        this.isCitrus = isCitrus;
    }

    private hiFrase(): string {
        return "Hi! I\'m an aplle and my name is " + this.name + " and I'm " + (this.isCitrus ? "" : " not ") + "citrus";
    }

    public sayHi() {
        alert(this.hiFrase())
    }
}
Fenton
  • 241,084
  • 71
  • 387
  • 401
  • 2
    Then how can we force children classes to follow same methods to implement ? – 9me Oct 24 '20 at 11:16
  • The method on the base class cannot be both abstract and private - it makes no sense because how can it be "private to the abstract class" if you want it to be implemented in the sub class? It has to be at least protected in the abstract class. – Fenton Oct 28 '20 at 15:23
  • 1
    use case is you want to force children classes to implement same private function. that abstract method will stay private but definition will come from abstract class. – 9me Nov 02 '20 at 05:22
  • Why should it be this.isCitrus? @Fenton – SLLegendre Apr 10 '21 at 16:20
  • 1
    @SLLegendre because inside of the `private hiFrase(): string` method, you have to prefix member names with `this.` - it's a compiler error otherwise. – Fenton Apr 16 '21 at 14:28
  • Ah thank you! was looking at the wrong isCitrus :D My apologies. – SLLegendre Apr 16 '21 at 21:02
  • No problem at all :) – Fenton Apr 18 '21 at 08:53
  • As I understand, forcing children class to have private methods breaks one of the OOP laws (incapsulation). Class decides itself what and how should be implemented inside and external class usage just follow public contract: methods / properties. The same for abstract parent, if we define method as private, it becomes method for the only this class and descendants don't need to rely on it – Dmitry May 31 '23 at 13:22