Ervadac
Ervadac

Reputation: 956

Add a method to all subclasses without changing the parent class

I have an abstract class A, B and C both inherit A

Now I want to extend both B and C with the same methods, so basically I'd like B and C to inherit a class ExtendedA, but I don't want to change A, B and C

It could work with mixins however since A is abstract, the mixin function has no way to know that the abstract methods are actually implemented in B and C, so naturally it gives me an error:

abstract class A {
    protected a = 1;

    public abstract hello(): void;
}

class B extends A {
    public hello() {
        console.log('hello from B');
    }
}

class C extends A {
    public hello() {
        console.log('hello from C');
    }
}

type AConstructor = new(...args: any[]) => A;

function ExtendedA<T extends AConstructor>(Base: T) {
    return class extends Base {
        public doSomething() {
            this.hello();
            console.log('do something', this.a);
        }
    }
}


class ExtendedB extends ExtendedA(B) {
}

class ExtendedC extends ExtendedA(C) {
}

const d = new D();
const e = new E();

d.doSomething();
// hello from B
// do something 1
e.doSomething();
// hello from C
// do something 1

test.ts:22:12 - error TS2653: Non-abstract class expression does not implement inherited abstract member 'hello' from class 'A'.

am I not seeing something or is there no way to do it in typescript?

Upvotes: 1

Views: 533

Answers (1)

adrisons
adrisons

Reputation: 3723

Your problem is that AConstructor defines a type that extends A, and ExtendedA is extending that type, but no class is implementing A (which is abstract) methods. Try using an interface instead:


interface AInterface {
    hello();
}

type AConstructor = new (...args: any[]) => AInterface;

let ExtendedA = (Base: AConstructor): any => {
  return class extends Base {
    public doSomething() {
      this.hello();
      console.log("do something", this.a);
    }
  };
};

Note: protected property is not accesible from grandchildren, only for children.

Upvotes: 2

Related Questions