Typescript :: Conditional chaining function

Removing the some functions is simple, you can just use Omit<this, 'specialPlus'> If we test this it almost works, if you call specialPlus you will get an error if you call it immediately after another call to specialPlus, you can however call it after a call to specialMinus

interface ISpecialCalculator extends ISimpleCalculator {
  specialPlus(value: number): Omit<this, 'specialPlus'>;
  specialMinus(value: number): Omit<this, 'specialMinus'>;
}

declare let testCalculator: ISpecialCalculator;
testCalculator  
  .specialPlus(40)
   // .specialPlus(40) // error 
  .specialMinus(20)
  .specialPlus(40) //ok 
  .sum()

Playground Link

This is because Omit will work on the this type bound when testCalculator is declared, so specialMinus will return in fact Omit<ISpecialCalculator, 'specialMinus'> which will still contain specialPlus even though we previously removed it. What we want is for Omit to work on the type of this returned by the previous function. We can do this if we capture the actual type of this for each call using a generic type parameter, and Omit methods from this type parameter not from polymorphic this.

interface ISimpleCalculator {
  plus<TThis>(this: TThis,value: number): TThis;
  minus<TThis>(this: TThis,value: number): TThis;
  divide<TThis>(this: TThis,value: number): TThis;
  multiply<TThis>(this: TThis,value: number): TThis;
  sum(): void
}

interface ISpecialCalculator extends ISimpleCalculator {
  specialPlus<TThis>(this: TThis, value: number): Omit<TThis, 'specialPlus'>;
  specialMinus<TThis>(this: TThis, value: number): Omit<TThis, 'specialMinus'>;
}

declare let testCalculator: ISpecialCalculator;
testCalculator
  .specialPlus(40)
  // .specialPlus(40) // error 
  .specialMinus(20)
  .plus(10)
  .specialPlus(40) // also error 
  .plus(10)
  .sum()

Playground Link