【问题标题】:Typescript :: Conditional chaining functionTypescript :: 条件链接函数
【发布时间】:2019-12-10 07:04:55
【问题描述】:

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

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()

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

【问题讨论】:

  • 我认为这在 typescript 中是不可能的,你需要 JavaScript 运行时实现来实现这样的功能
  • Imo 你必须实现一个具体的类,然后它工作正常:typescriptlang.org/play/index.html#code/…
  • 嗨@r3dst0rm,实际上结果是一样的。不要忘记ISpecialCalculator 接口包含多个函数,每个函数只允许使用一次。

标签: typescript chaining


【解决方案1】:

删除一些函数很简单,你可以使用Omit&lt;this, 'specialPlus'&gt; 如果我们测试它几乎可以工作,如果你调用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 在声明testCalculator 时将作用于this 类型绑定,因此specialMinus 实际上将返回Omit&lt;ISpecialCalculator, 'specialMinus'&gt;,即使我们之前删除了它,它仍将包含specialPlus。我们想要的是Omit 处理上一个函数返回的this 类型。如果我们使用泛型类型参数为每个调用捕获this 的实际类型,并且从这个类型参数而不是来自多态thisOmit 方法,我们可以做到这一点。

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

【讨论】:

  • 嗨@Titian,我以前尝试过与您相同的方法。就像你说的那样,它“几乎”有效 :) 但别忘了我们仍然可以在 specialPlusspecialMinus 之间添加 plus minus ...。
  • @NelsonTang 哎呀,我的错。固定的。您还需要对其他函数应用相同的通用处理,只要它们返回 TThis
  • 哦!!!!我只是明白了!你说的太对了!我想要的是前一个函数返回的this。我低估了this 的力量。你救了我的天师@Titian!
【解决方案2】:
specialPlus(value: number): ISimpleCalculator;

当您调用此函数时,您将得到一个不再具有特殊功能的简单计算器。特殊接口也应该返回this,它应该可以工作:

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

【讨论】:

  • 嗨@amit,我放ISimpleCalculator的原因是我想限制ISpecialCalculator中的功能只能使用一次。
【解决方案3】:

尝试以下(根据问题测试的完整代码):

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): this
  specialMinus(value: number): this
}

let testCalculator: ISpecialCalculator
testCalculator
  .plus(20)
  .multiply(2)
  .specialPlus(40)
  .plus(20)
  .minus(5)
  .specialMinus(20) 
  .sum()

如果您想限制 special[Plus|Minus] 的使用,那么您可以在实现 ISpecialCalculator 的具体类中完成此操作界面。

下面的代码可能会给你一些想法:

class Calculator implements ISpecialCalculator {
  specialPlusUsed = false
  specialMinusUsed = false

  specialPlus(value: number): this {
    if (this.specialPlusUsed) throw new Error("SpecialPlus can be used only once!")

    this.specialPlusUsed = true
    // Related calculations here...
    return this
  }

  specialMinus(value: number): this {
    if (this.specialMinusUsed) throw new Error("SpecialMinus can be used only once!")
    this.specialMinusUsed = true
    // Related calculations here...
    return this
  }

  plus(value: number): this {
    // Related calculations here...
    return this
  }

  minus(value: number): this {
    // Related calculations here...
    return this
  }

  divide(value: number): this {
    // Related calculations here...
    return this
  }

  multiply(value: number): this {
    // Related calculations here...
    return this
  }

  sum(): void {
    // Related calculations here...
  }
}

【讨论】:

  • 嗨 Ben Dev,你的答案和上面的@amit 一样。 ISpecialCalculator中的函数只能使用一次。
  • @NelsonTang 接口定义了一个契约,你不能限制它们在应用程序中的使用次数!
  • @NelsonTang 查看实现“ISpecialCalculator”接口的示例代码。希望对您有所帮助。
  • 嗨@BenDev,我完全理解你的方法,但我想要实现的是通过类型保护阻止用户,而不是在运行时。
猜你喜欢
  • 1970-01-01
  • 2014-07-05
  • 1970-01-01
  • 2018-07-04
  • 2018-09-06
  • 2021-01-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多