我有用于 rxjs 可观察量的自定义通用钩子。现在看起来像这样:
type Params<T> = {
observable$: Observable<T> | null;
next: (value: T) => void;
};
export const useSubscription = <T>({
observable$,
next,
}: Params<T>) => {
const nextCallback = useCallbackRef(next);
useEffect(() => {
if (!observable$) {
return undefined;
}
const sub = observable$.subscribe(nextCallback);
return () => sub.unsubscribe();
}, [observable$, nextCallback]);
};
它工作正常,但现在我正在尝试向
select
添加可选的通用 Params
功能。我打算将它与 rxjs map
运算符一起使用。 select
应将 T
作为输入并返回某种类型 R
,然后将其传递给 next
函数。如果未提供 select
,则 next
的输入类型应为之前的 T
。因此,可能的参数选项大致应如下所示:
type Params<T, R> = {
observable$: Observable<T> | null;
next: (value: T) => void;
} | {
observable$: Observable<T> | null;
next: (value: R) => void;
select: (value: T) => R;
};
我尝试使用条件类型、函数重载来实现此目的,但无法实现。
请参阅下面的一些解释:
type ParamsA<T> = {
observable$: T;
next: (value: T) => void;
}
type ParamsB<T, R> = {
observable$: T;
next: (value: R) => void;
select: (value: T) => R;
}
type Params<T, R = undefined> = R extends undefined ? ParamsA<T> : ParamsB<T, R>;
const a: Params<number> = {
observable$: 1,
next: (value) => { console.log(value); },
} // OK: value --> number
const b: Params<number, string> = {
observable$: 1,
next: (value) => { console.log(value); },
} // ERROR: Property 'select' is missing in type '{ observable$: number; next: (value: string) => void; }' but required in type 'ParamsB<number, string>'
const c: Params<number, string> = {
observable$: 1,
next: (value) => { console.log(value); },
select: (value) => 'a',
} // OK: next value --> string, select value --> number
const d: Params<number> = {
observable$: 1,
next: (value) => { console.log(value); },
select: (value) => 'a',
} // ERROR: Object literal may only specify known properties, and 'select' does not exist in type 'ParamsA<number>'.
因此,我们将
Params
分成它可以采用的两种可能的形式,并使用 条件类型 来根据是否传递了泛型参数 R
来确定哪一种形式。通过将 R
参数的 默认值设置为未定义,它变成可选的,从而使
select
属性仅在传递 R
时才需要。