我正在尝试实现一组链接函数,但是不知何故我被卡在了这里。

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

interface ISpecialCalculator extends ISimpleCalculator {
  specialPlus(value: number): ISimpleCalculator;
  specialMinus(value: number): ISimpleCalculator;
}

let testCalculator: ISpecialCalculator;
testCalculator
  .plus(20)
  .multiply(2)
  .specialPlus(40)
  .plus(20)
  .minus(5)
  .specialMinus(20)  //<-- Error! Property 'specialMinus' does not exist on type 'ISimpleCalculator'.
  .sum()


我想在链中归档函数的类型检查。在上面的示例中,我希望specialPlus中的函数specialMinusISpecialCalculator只能使用一次,而ISimpleCalculator可以多次使用。我对打字稿非常了解,我一直在尝试不同的方法(高级类型(PickOmit)),但到目前为止没有成功。我想知道在这种情况下还有其他方法可以提供帮助。

最佳答案

删除某些功能很简单,您可以使用Omit<this, 'specialPlus'>如果我们测试了一下它几乎可以正常工作,如果您调用specialPlus,则在再次调用specialPlus之后立即调用它会收到错误消息,但是您可以调用呼叫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

这是因为Omit在声明this时将在testCalculator类型绑定上起作用,因此specialMinus实际上将返回Omit<ISpecialCalculator, 'specialMinus'>,尽管我们先前已将其删除,但它仍包含specialPlus。我们想要的是Omit在上一个函数返回的this类型上工作。如果我们使用通用类型参数捕获每个调用的this的实际类型,并且使用此类型参数的Omit方法而不是多态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

08-19 15:04