[英]Typescript Function Overload Incompatibility
我一直在實現 NgRx 商店,發現自己使用了該模式
concatMap(action => of(action).pipe(
withLatestFrom(this.store.pipe(select(fromBooks.getCollectionBookIds)))
)),
(從https://ngrx.io/guide/effects底部開始)
考慮到它會占用多少空間,我想編寫一個方便的實用程序運算符來處理它。
所以我想出了一個應該可行的實現:
export function concatMapLatestFrom<A extends Action>(
...xs: Array<ObservableInput<never>>
): OperatorFunction<A, unknown> {
return function (source: Observable<A>): Observable<unknown> {
return source.pipe(
concatMap((action) => of(action).pipe(withLatestFrom(...xs))),
);
};
}
我寫了一些正確類型的重載:
export function concatMapLatestFrom<X1, A extends Action>(
source1: ObservableInput<X1>,
): { (source1: X1): OperatorFunction<A, [A, X1]> };
export function concatMapLatestFrom<X1, X2, A extends Action>(
source1: ObservableInput<X1>,
source2: ObservableInput<X2>,
): { (source1: X1, source2: X2): OperatorFunction<A, [A, X1, X2]> };
export function concatMapLatestFrom<X1, X2, X3, A extends Action>(
source1: ObservableInput<X1>,
source2: ObservableInput<X2>,
source3: ObservableInput<X3>,
): {
(source1: X1, source2: X2, source3: X3): OperatorFunction<
A,
[A, X1, X2, X3]
>;
};
但由於某種原因,它認為重載簽名與實現不兼容。 如果我注釋掉其中一個,它會重復下一個。
它使我無法理解這實際上有什么問題,編譯器最好告訴我為什么它不兼容,但不幸的是它沒有提供任何細節。
我認為罪魁禍首是你在那里使用的never
和unknown
的類型。
所以,如果你有
of(1)
.pipe(
concatMapLatestFrom(of('john'), of(true))
).subscribe(observer)
那么,如果我理解正確, observer
應該收到一個[number, string, boolean]
元組。
據我所知, concatMapLatestFrom
並沒有說得很清楚:
function concatMapLatestFrom (): OperatorFunction<A, unknown> {}
因此,我們只得到了該元組的第一個元素,即源的類型。 剩下要做的是根據提供給concatMapLatestFrom
的ObservableInput
的類型來推斷其他類型的屬性。
考慮到這一點,這將是我的方法:
export function concatMapLatestFrom<
A extends Action,
U extends Array<ObservableInput<any>>,
R = Unshift<ObservedValueTupleFromArray<U>, A>
> (
...xs: U
): OperatorFunction<A, R> {
return function (source: Observable<A>): Observable<R> {
return source.pipe(
concatMap((action) => of(action).pipe(withLatestFrom(...xs))),
);
};
}
使用的類型可以從'rxjs'
導出:
// Mapped tuples: https://www.typescriptlang.org/docs/handbook/release-notes/typescript-3-1.html#mapped-types-on-tuples-and-arrays
// E.g [Observable<number>, Observable<string>] --> [number, string]
export type ObservedValueTupleFromArray<X> =
X extends Array<ObservableInput<any>>
? { [K in keyof X]: ObservedValueOf<X[K]> }
: never;
// Simply extract the value
export type ObservedValueOf<O> = O extends ObservableInput<infer T> ? T : never;
// Unshift<[B, C], A> --> [A, B, C]
export type Unshift<X extends any[], Y> =
((arg: Y, ...rest: X) => any) extends ((...args: infer U) => any)
? U
: never;
當您使用重載時,類型信息來自重載,實現只需要處理所有可能的參數。 arguments 類型和返回類型將根據所選的重載而改變,因此將其排除在外可能會解決問題。
export function concatMapLatestFrom(
...xs: Array<ObservableInput<never>>
) {
return function(source: Observable<any>): Observable<unknown> {
return source.pipe(
concatMap(action => of(action).pipe(withLatestFrom(...xs)))
);
};
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.