TypeScript: Can not declare protected methods without implementation in TS 2.0

Sometimes I use mixins to share some protected logic between several classes:

class Mixin {
    protected doSomething(): void {
    }
}

class Base {
}

class Sample extends Base {
    run() {
        this.doSomething();
    }

    protected doSomething(): void; // error TS2391: Function implementation is missing or not immediately following the declaration.
}

// uncomment the following code to fix the complilation in v1.8 and earlier
//namespace Sample {
//}

// extend Sample.prototype from Mixin.prototype

The code above raises the error TS2391. But uncommenting namespace Sample after the class definition changed behavior: the compilation became successful before version 2.0. Maybe it was a bug or undocumented feature, I don’t know. But it worked and I used it since early versions (about 1.3 or 1.4), including 1.8.10. This behavior changed in 2.0, now introducing the namespace don’t fix compilation:(

I can declare mixining method as a property:

class Sample extends Base {
    protected doSomething: () => void;
}

But in this case I can’t override this method later:

class Child extends Sample {
    protected doSomething(): void { // error TS2425: Class 'Sample' defines instance member property 'doSomething', but extended class 'Child' defines it as instance member function.
        super.doSomething(); //  error TS2340: Only public and protected methods of the base class are accessible via the 'super' keyword.
    }
}

Also this way is inconvenient and confusing.

If method doSomething would be public, I can declare it in interface Sample and TypeScript merge it with the class. But this trick does not work with protected methods.

I tried to mark the method as optional (although it is mandatory in fact):

    protected doSomething?(): void;

But now compilation with --strictNullChecks throws an error error TS2532: Object is possibly 'undefined'.

The only workaround that I found is to add a fake implementation to the method:

    protected doSomething(): void { }

But this generates redundant JavaScript and misleads code reviewers. Unacceptable:( So this is real blocker for me to update to version 2.0.

Adding a namespace with the same name was not clean of course. The solution would be to allow using declare inside a class body:

class Sample extends Base {
    run() {
        this.doSomething();
    }

    declare protected doSomething(): void;
}

I suppose it is not so difficult to implement this.

P.S. Sorry for my English:(

About this issue

  • Original URL
  • State: closed
  • Created 8 years ago
  • Comments: 17 (6 by maintainers)

Most upvoted comments

in cases of conflicting declarations, you will have to redefine them in the interface. doing so changing the visibility to public though. do not think there is a way around this.

Do I understand right that an interface can also have the inherited protected members if it extends a class?

yes, the interface inherits all the members from the class. protected and private members can only be declared in a class though. so this is the only way an interface can get a protected or a private member.