具有打字稿联合类型的 RxJS 自定义运算符
RxJS Custom operator with typescript Union type
我有以下型号:
export interface IModel<T> {
exp: number,
value: T
}
我想创建一个自定义 RxJS 运算符,例如:
private customOperator<U extends A | B, T extends IModel<U>>(custom: Observable<T>): Observable<U> {
return custom.pipe(map((x: T) => x.value ));
}
但是我在使用的时候遇到了类型错误:
mySub: = new Subject<IModel<A>>;
myObs$: Observable<A> = this.mySub.asObservable().pipe(this.customOperator); // <== ERROR
错误:无法将类型 'Observable<A | B>' 分配给类型 'Observable< A>'。
知道如何更改我的自定义运算符来避免该问题吗?
将运算符包装在工厂函数中。
private customOperator<T extends IModel<U>, U extends A | B> () {
return (custom: Observable<T>): Observable<U> =>
custom.pipe(map((x: T) => x.value ));
}
然后在管道中使用运算符作为函数调用而不是函数引用。
myObs$: Observable<A> = this.mySub.asObservable().pipe(this.customOperator());
干杯
您需要使用 Typescript type assertion 功能。
在你的情况下,编译器会抱怨,因为 myObs$
必须 是 Observable<A>
类型,而你的自定义运算符可以 return Observable<A>
或 Observable<B>
.
因此,如果您想避免错误,您需要向 Typescript 保证您的自定义运算符肯定会 return 和 Observable<A>
。这是避免对 Typescript 编译器进行合法检查的技巧,因此您最好确保自己做的事情是正确的。
所以代码应该是这样的
myObs$: Observable<A> = this.mySub.asObservable().pipe(this.customOperator) as Observable<A>;
或者,更简单地说
myObs$ = this.mySub.asObservable().pipe(this.customOperator) as Observable<A>;
如果您将鼠标悬停在 myObs$
上,例如在 VSCode 内,您将看到为 myObs$
推断的类型实际上是 Observable<A>
,即使您没有指定类型(至少在代码的最后一个版本中)
更新基于@akotech 回复
处理这种情况的更好方法是@akotech 提出的方法。
customOperator
编码如下 returns 和 Observable<U>
private customOperator<T extends IModel<U>, U extends A | B> () {
return (custom: Observable<T>): Observable<U> =>
custom.pipe(map((x: T) => x.value ));
}
有趣的是,至少在我的情况下,如果我没有像这一行那样声明 myObs$
的类型
myObs$ = mySub.pipe(customOperator_())
myObs$
的推断类型是 Observable<A | B>
,但与此同时,如果我尝试这样的事情
myObs$: : Observable<B> = mySub.pipe(customOperator_())
我从编译器中得到一个错误 Type 'Observable<IModel>' is not assignable to type 'Observable<IModel>',这是正确的,因为 mySub
通知对象类型 IModel<A>
.
同时,如果我尝试这样的事情
myObs$: : Observable<A> = mySub_A.pipe(customOperator_())
编译器没有引发错误,这也是正确的。
所以@akotech提出的方案比我提出的方案更安全
我有以下型号:
export interface IModel<T> {
exp: number,
value: T
}
我想创建一个自定义 RxJS 运算符,例如:
private customOperator<U extends A | B, T extends IModel<U>>(custom: Observable<T>): Observable<U> {
return custom.pipe(map((x: T) => x.value ));
}
但是我在使用的时候遇到了类型错误:
mySub: = new Subject<IModel<A>>;
myObs$: Observable<A> = this.mySub.asObservable().pipe(this.customOperator); // <== ERROR
错误:无法将类型 'Observable<A | B>' 分配给类型 'Observable< A>'。
知道如何更改我的自定义运算符来避免该问题吗?
将运算符包装在工厂函数中。
private customOperator<T extends IModel<U>, U extends A | B> () {
return (custom: Observable<T>): Observable<U> =>
custom.pipe(map((x: T) => x.value ));
}
然后在管道中使用运算符作为函数调用而不是函数引用。
myObs$: Observable<A> = this.mySub.asObservable().pipe(this.customOperator());
干杯
您需要使用 Typescript type assertion 功能。
在你的情况下,编译器会抱怨,因为 myObs$
必须 是 Observable<A>
类型,而你的自定义运算符可以 return Observable<A>
或 Observable<B>
.
因此,如果您想避免错误,您需要向 Typescript 保证您的自定义运算符肯定会 return 和 Observable<A>
。这是避免对 Typescript 编译器进行合法检查的技巧,因此您最好确保自己做的事情是正确的。
所以代码应该是这样的
myObs$: Observable<A> = this.mySub.asObservable().pipe(this.customOperator) as Observable<A>;
或者,更简单地说
myObs$ = this.mySub.asObservable().pipe(this.customOperator) as Observable<A>;
如果您将鼠标悬停在 myObs$
上,例如在 VSCode 内,您将看到为 myObs$
推断的类型实际上是 Observable<A>
,即使您没有指定类型(至少在代码的最后一个版本中)
更新基于@akotech 回复
处理这种情况的更好方法是@akotech 提出的方法。
customOperator
编码如下 returns 和 Observable<U>
private customOperator<T extends IModel<U>, U extends A | B> () {
return (custom: Observable<T>): Observable<U> =>
custom.pipe(map((x: T) => x.value ));
}
有趣的是,至少在我的情况下,如果我没有像这一行那样声明 myObs$
的类型
myObs$ = mySub.pipe(customOperator_())
myObs$
的推断类型是 Observable<A | B>
,但与此同时,如果我尝试这样的事情
myObs$: : Observable<B> = mySub.pipe(customOperator_())
我从编译器中得到一个错误 Type 'Observable<IModel>' is not assignable to type 'Observable<IModel>',这是正确的,因为 mySub
通知对象类型 IModel<A>
.
同时,如果我尝试这样的事情
myObs$: : Observable<A> = mySub_A.pipe(customOperator_())
编译器没有引发错误,这也是正确的。
所以@akotech提出的方案比我提出的方案更安全