我正在编写一个RxJS运算符,它等待输入运算符完成,然后对第二个运算符执行switchMap
(与switchMap
一样动态生成)。我想出了我的代码的两个版本,一个版本有效,一个版本无效,而我正竭尽全力去解释为什么这样做。
有效版本:
import { Observable } from "rxjs"; // OperatorFunction,
import { defaultIfEmpty, last, switchMap } from "rxjs/operators";
// This definition of OperatorFunction is more or less equivalent to the
// definition in rxjs/src/internal/types.ts
interface OperatorFunction<T, S> {
(input: Observable<T>): Observable<S>;
}
interface ObservableGenerator<T, S> {
(value: T): Observable<S>;
}
export function switchMapComplete<T, S>(project: ObservableGenerator<T, S>): OperatorFunction<T, S> {
function mapper(obs1: Observable<T>): Observable<S> {
return obs1.pipe(
defaultIfEmpty(null),
last(),
switchMap(project)
);
}
return mapper;
}
无效的版本(请注意,唯一更改的是OperatorFunction
和OperatorGenerator
的定义):
import { Observable } from "rxjs";
import { defaultIfEmpty, last, switchMap } from "rxjs/operators";
type OperatorFunction2<T, S> = <T, S>(obs: Observable<T>) => Observable<S>;
type ObservableGenerator2<T, S> = <T, S>(value: T) => Observable<S>;
export function switchMapComplete2<T, S>(project: ObservableGenerator2<T, S>): OperatorFunction2<T, S> {
function mapper(obs1: Observable<T>): Observable<S> {
return obs1.pipe(
defaultIfEmpty(null),
last(),
switchMap(project)
);
}
return mapper;
}
后一版本导致编译器引发以下异常:
error TS2322: Type 'Observable<{}>' is not assignable to type 'Observable<S>'.
Type '{}' is not assignable to type 'S'.
util.ts(49,5): error TS2322: Type '(obs1: Observable<T>) => Observable<S>' is not assignable to type 'OperatorFunction2<T, S>'.
Types of parameters 'obs1' and 'obs' are incompatible.
Type 'Observable<T>' is not assignable to type 'Observable<T>'. Two different types with this name exist, but they are unrelated.
Type 'T' is not assignable to type 'T'. Two different types with this name exist, but they are unrelated.
我对此感到非常惊讶,并且花了很长时间才提出TypeScript文档say that both versions should be equivalent的工作版本(据我了解)。
我很感谢有任何关于为什么我的等效性失效的指示。
PS:对于需要类似于我的RxJS运算符的任何人,这是另一个(有效的)解决方案,它稍微简单一些,并充分利用了RxJS已经提供的类型:
import { Observable, ObservableInput, OperatorFunction, pipe } from "rxjs";
import { defaultIfEmpty, last, switchMap } from "rxjs/operators";
export function switchMapComplete<T, S>(project: (value: T) => ObservableInput<S>): OperatorFunction<T, S> {
return pipe(
defaultIfEmpty(null),
last(),
switchMap(project)
);
}
答案 0 :(得分:3)
首先,应将类型OperatorFunction2<T, S> = <T, S>(obs: Observable<T>) => Observable<S>
更改为type OperatorFunction2 = <T, S>(obs: Observable<T>) => Observable<S>
,因为在类型别名的定义中未使用外部T
或S
。内部的<T, S>
遮盖了外部名称。并对ObservableGenerator2
进行类似的更改。
请注意,type F<T> = (x:T) => void
不等于type G = <T>(x:T)=>void
。 TypeScript不允许完全generic values。类型F
是泛型的,是指具体功能,并且必须为F
提供要使用的类型参数(F
不好,F<string>
很好)。类型G
是引用泛型函数的具体类型,不能为G
提供类型参数(G<string>
不好,G
好)。类型为F<string>
的值是具体的,只能接受string
函数输入。类型为G
的值是通用的,可以接受任何输入。
不是类型完全不相关;他们只是不相等。我希望可以为您提供更多帮助,但是我没有在任何地方安装RxJS,因此以下代码可能仍然有错误。不过,我会在这里告诉您我会尝试什么:
// concrete types referring to generic functions
type OperatorFunction2 = <T, S>(obs: Observable<T>) => Observable<S>;
type ObservableGenerator2 = <T, S>(value: T) => Observable<S>;
// a concrete function which takes a generic function and returns a generic function
export function switchMapComplete2(project: ObservableGenerator2): OperatorFunction2 {
// a generic function
function mapper<T, S>(obs1: Observable<T>): Observable<S> {
return obs1.pipe(
defaultIfEmpty(null),
last(),
switchMap(project)
);
}
return mapper;
}
希望能使您走上正确的道路。您可能需要深入研究mapper
并修复更多签名。无论如何,祝你好运!
答案 1 :(得分:2)
TypeScript中的通用函数类型通常写为
type OperatorFunction2<T, S> = (obs: Observable<T>) => Observable<S>;
语法
type OperatorFunction2 = <T, S>(obs: Observable<T>) => Observable<S>;
泛型参数在类型定义中出现“内联”的情况也是有效的,但是由于某种原因,它与泛型参数为类型显式给出的类型定义并不完全等效。当您没有嵌套通用参数的type
定义时,当您必须在嵌套在另一个定义中的类型注释中提供显式类型时,第二种形式有时会很有用。
当您将两者结合在一起时
type OperatorFunction2<T, S> = <T, S>(obs: Observable<T>) => Observable<S>;
然后,如jcalz所指出的,您将获得两组独立的通用参数集,它们的名称分别为T
和S
,彼此无关。
对于您的示例,您可以只使用第一种语法:
import { Observable } from "rxjs";
import { defaultIfEmpty, last, switchMap } from "rxjs/operators";
type OperatorFunction2<T, S> = (obs: Observable<T>) => Observable<S>;
type ObservableGenerator2<T, S> = (value: T) => Observable<S>;
export function switchMapComplete2<T, S>(project: ObservableGenerator2<T, S>): OperatorFunction2<T, S> {
function mapper(obs1: Observable<T>): Observable<S> {
return obs1.pipe(
defaultIfEmpty(null),
last(),
switchMap(project)
);
}
return mapper;
}