I have a code where I’m doing some statistics over some variables. It basically is the same code but duplicated over and over so I’ve decided to provide a nice abstraction.

The problem is that those statistics are performed over value objects so I need to define an interface for those objects to allow for the abstraction.

My 2 current value objects are Money and Time and I want to be able to plug them into a class like the following (the abstracted code):

class Average<T extends Operable> {
   private value: T;
   private count: number;

   public constructor(init: T) {
      this.value = init;
      this.count = 0;
   }

   public add(value: T): void {
      this.value = this.value.add(value);
      this.count++;
   }

   public getAverage(): T {
      return this.value.divide(Math.max(1, this.count));
   }
}

For this, I need, of course, the Operable interface that Money and Time need to extend from so I went ahead and attempted to create it:

interface Operable {
   add(value: Operable): Operable;
   divide(value: number): Operable;
}

This, however, is not quite what I want because it would allow for Money and Time to be cross-operated (f.e. const m = new Money(); const t = new Time(); m.add(t);). In addition to this, my IDE rightfully complaints about this on Average.add method:

Type 'Operable' is not assignable to type 'T'.
     'Operable' is assignable to the constraint of type 'T', but 'T' could be instantiated with a different subtype of constraint 'Operable'.

A few Google searches later I learnt that you can use this in an interface to refer to the instance type so I changed the interface as follows:

interface Operable {
   add(value: this): this;
   divide(value: number): this;
}

This clears the error in Average.add but pushes it to the value object’s methods (here is an example for Money.add):

Property 'add' in type 'Money' is not assignable to the same property in base type 'Operable'.
     Type '(money: Money) => Money' is not assignable to type '(value: this) => this'.
       Type 'Money' is not assignable to type 'this'.
         'Money' is assignable to the constraint of type 'this', but 'this' could be instantiated with a different subtype of constraint 'Money'.

Is there a way to get this sort of construction working in Typescript? Many thanks!

Edit: please, note that my value objects are immutable so changing the Average.add method to just this.value.add(value); is not an option.