[英]Typescript :: Conditional chaining function
I'm trying to implement a set of chained function but somehow I get stuck here.我正在尝试实现一组链式函数,但不知何故我卡在这里了。
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()
I want to archive type check of the function in the chain.我想归档链中函数的类型检查。 In the above example, I want the functions specialPlus
and specialMinus
in ISpecialCalculator
to be used once only and ISimpleCalculator
can be used for multiple times.在上述例子中,我想要的功能specialPlus
和specialMinus
在ISpecialCalculator
进行一次仅使用和ISimpleCalculator
可用于多次。 I'm pretty fresh to the typescript and I've been trying different approaches (Advanced type ( Pick
& Omit
)) with no success so far.我对打字稿很陌生,到目前为止我一直在尝试不同的方法(高级类型( Pick
& Omit
))但没有成功。 I want to know is there any other way to help in this case.我想知道在这种情况下有没有其他方法可以提供帮助。
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
删除一些函数很简单,你可以使用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()
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.这是因为Omit
将在工作this
类型时势必testCalculator
声明,所以specialMinus
实际上将返回Omit<ISpecialCalculator, 'specialMinus'>
这仍将包含specialPlus
即使我们以前删除它。 What we want is for Omit
to work on the type of this
returned by the previous function.我们想要的是让Omit
处理前一个函数返回的this
类型。 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
.我们可以做到这一点,如果我们捕获的实际类型的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()
specialPlus(value: number): ISimpleCalculator;
When you call this function, you are getting back a simple calculator that doesn't have the special functions anymore.当您调用此函数时,您将返回一个不再具有特殊功能的简单计算器。 The special interface should also return this
and it should be working:特殊接口也应该返回this
并且它应该可以工作:
interface ISpecialCalculator extends ISimpleCalculator {
specialPlus(value: number): this;
specialMinus(value: number): this;
}
Try the following (full code tested based on the question):尝试以下操作(基于问题测试的完整代码):
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()
If you want to limit the special[Plus|Minus] usage then you can accomplish that in the concrete class that implements the ISpecialCalculator interface.如果您想限制特殊 [Plus|Minus] 的使用,那么您可以在实现ISpecialCalculator接口的具体类中实现。
The code below may give you some ideas:下面的代码可能会给你一些想法:
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...
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.