[英]Writing a custom ngrx operator and returning the source observable type
I have a custom operator, waitFor
which I am using in my effects as so:我有一个自定义运算符,
waitFor
我在我的效果中使用它:
public effect$: Observable<Action> = createEffect(() => {
return this.actions$.pipe(
ofType(myAction),
waitFor<ReturnType<typeof myAction>>([anotherAction]),
...etc
);
});
It basically looks at correlationId's to not continue executing until the array of actions have been dispatched.它基本上着眼于correlationId,直到动作数组被分派后才继续执行。 But that is beside the point here.
但这不是重点。
As expected ofType
takes the source observable and uses this as the return type, however I am struggling to achieve the same effect.正如预期的那样,
ofType
采用源 observable 并将其用作返回类型,但是我正在努力实现相同的效果。 As you can see above I am using ReturnType<typeof myAction>>
and the following in my waitFor
method:正如您在上面看到的,我在我的
waitFor
方法中使用ReturnType<typeof myAction>>
和以下内容:
export function waitFor<A extends Action>(actionsToWaitFor$: Array<Actions>): OperatorFunction<A, A> {
So at the moment if I call waitFor
like this:所以目前如果我这样调用
waitFor
:
public effect$: Observable<Action> = createEffect(() => {
return this.actions$.pipe(
ofType(myAction),
waitFor([anotherAction]),
...etc
);
});
Then its type is inferred as Action
, but I want this to be ReturnType<typeof theSourceObservable>
by default.然后它的类型被推断为
Action
,但我希望它默认为ReturnType<typeof theSourceObservable>
。 So I would assume I would need something like this in my waitFor
method:所以我假设我的
waitFor
方法中需要这样的东西:
export function waitFor<A extends ReturnType<typeof sourceObservable?!>>(actionsToWaitFor$: Array<Actions>): OperatorFunction<A, A> {
waitFor
looks like this: waitFor
看起来像这样:
export function waitFor<A extends Action>(actionsToWaitFor$: Array<Actions>): OperatorFunction<A, A> {
return (source$) => {
return source$.pipe(
switchMap((action: A & { correlationId: string}) => {
// use zip() to wait for all actions
// and when omitting map((action) => action)
// so the original action is always returned
})
);
};
}
From the ofType
source , it looks like I need to use Extract
从
ofType
来源看来,我需要使用Extract
This, at least, compiles;这至少可以编译; I don't know if it also does what you need.
我不知道它是否也能满足您的需求。
public effect3$: Observable<Action> = createEffect(() => {
const a:Action[]= []
return this.actions$.pipe(
ofType(doSomething),
this.someCustomOperatorReturningStaticTypes(),
this.thisWontWork(a),
tap(({aCustomProperty}) => {
// The type is inferred
console.log(aCustomProperty);
}),
)
});
private thisWontWork<A extends Action>(actionsToWaitFor$: Action[]): OperatorFunction<A, A> {
return (source$) => {
return source$.pipe(
tap(() => {
console.log('Should work')
})
)
}
}
I wasn't able to run it in the StackBlitz, any hint?我无法在 StackBlitz 中运行它,有什么提示吗?
Hope this helps希望这可以帮助
Came across this question and I thought I'd add a couple explanations in case you are still wondering and if anyone comes across this in future!遇到这个问题,我想我会添加一些解释,以防您仍然想知道将来是否有人遇到这个问题!
If you want to infer something as the type it is passed as (eg here you want your action to be returned as the type it is) you just return the same generic which you pass in - as the answer says like:如果您想推断某些东西作为它传递的类型(例如,在这里您希望您的操作作为它的类型返回),您只需返回您传入的相同泛型 - 正如答案所说的那样:
function foo<A>(val: A): A {
return val;
}
If I call foo() with a number, I get a number back.如果我用数字调用 foo(),我会得到一个数字。 If I call it with a specific action type, then the same thing happens.
如果我用特定的动作类型调用它,那么同样的事情也会发生。 This is why you just need the return
type OperatorFunction<A, A>
- same thing in, same thing out.这就是为什么你只需要返回
type OperatorFunction<A, A>
- 同样的东西,同样的东西。
The key here is that you need some set of actions which you are narrowing.这里的关键是你需要一些你正在缩小的行动。
Using createAction takes care of this for you, but for example's sake I'll create this by hand.使用 createAction 会为您解决这个问题,但例如,我将手动创建它。
type FooAction = { type: 'FOO_ACTION' };
type BarAction = { type: 'BAR_ACTION' };
// This type gets built by you using createAction - this is your Action type
type MyActions = FooAction | BarAction;
Next we need a type which is going to take our set of actions ( MyActions
) - and narrow it to a specific action based on the type.接下来,我们需要一个类型来执行我们的操作集(
MyActions
) - 并根据类型将其缩小到特定的操作。
type NarrowActionType<T extends { type: any }, K extends string> = T extends { type: K }
? T
: never;
We can verify this works:我们可以验证这是否有效:
type NarrowedActionTest = NarrowActionType<MyActions, 'FOO_ACTION'>;
ofType is a higher order function which first accepts a string, and then the observable stream to operate on. ofType 是一个更高阶的 function ,它首先接受一个字符串,然后是可观察的 stream 进行操作。 I'm not going to use observables to keep it simpler, but it's the same principle.
我不会使用 observables 来保持它更简单,但这是相同的原理。
In essence we want something along the lines of (type: string) => (action: Action) => action is NarrowActionType
for the type signature.本质上,我们想要类似于
(type: string) => (action: Action) => action is NarrowActionType
的类型签名。
A
A
T
T
T
extends string T
扩展了字符串T
to begin with, and then the type of A
once the object stream is applied, so let's use one generic parameter at each function applicationT
的类型开始,然后A
的类型一旦 object stream 被应用,所以让我们在每个 function 应用程序中使用一个通用参数A.type
is the same as type. A.type
是否与 type 相同。 So we should enforce this exists, with A extends { type: any }
A extends { type: any }
function isOfType<T extends string>(type: T) {
return <A extends { type: any }>(action: A): action is NarrowActionType<A, T> => {
return action.type === type
}
}
Now we can test this function on a MyActions type, and see if it can narrow the output:现在我们可以在 MyActions 类型上测试这个 function,看看它是否可以缩小 output:
const myAction: MyActions = { type: 'FOO_ACTION' };
const isFooAction = isOfType('FOO_ACTION')(myAction);
if (isOfType('FOO_ACTION')(myAction)) {
type myNarrowedAction = typeof myAction; // is FooAction
}
Full playground link here: https://www.typescriptlang.org/play/#code/C4TwDgpgBAcghgJwQewO4EEDGwCWyB2AKuBADyFQQAewE+AJgM5QDeUokAXFHPiFAF8ANFADSlGnSZRGwBDnwBzAHxQAvFArVaDZmw4Ru4gQCgoUAPyazUbvggA3CAgDcJkwagAxZMiy4CdVZ2Em4Aci8AeUiAfXQAYUIASUiYMME3TwAhRH88fCD9UKgwrPQAJTjElLSM9xMAegbNAAscZk9FCGBmACMAVxwAG2AoXv4QZH6ofsYFRShMBAg4WjzAgFp2NuZ2qEn+hCh1goMPEigAWRAT5g0fP2x8qAAfKByEE7dzyFhEFFQEHoJ0IEFkQXgSDQIJIpGutxEEWiVWSqTCym+ADN+vgnoF2pFMcRIOQJDppLJ5EplAAKAzcQgASlYNnMy2AhwKpHQZKkehCXB4fEEtLgePw3HQjO4YoCBT2kIBMJJ6BEhFUalULFZ5l17M5PHFADpPGozQKIDrTKYTJgCOCALY3cXceHiu7BeklKKxBKo2oCNx2-Dg9oPE5BAlEkg0pG+6poxk0p0nRnfHCYqA0qPEiCxn0omphJMp8WM5na3UWqBOxVoIERjQGZCZ0tylxQJpQPbh8UmUxAA Full playground link here: https://www.typescriptlang.org/play/#code/C4TwDgpgBAcghgJwQewO4EEDGwCWyB2AKuBADyFQQAewE+AJgM5QDeUokAXFHPiFAF8ANFADSlGnSZRGwBDnwBzAHxQAvFArVaDZmw4Ru4gQCgoUAPyazUbvggA3CAgDcJkwagAxZMiy4CdVZ2Em4Aci8AeUiAfXQAYUIASUiYMME3TwAhRH88fCD9UKgwrPQAJTjElLSM9xMAegbNAAscZk9FCGBmACMAVxwAG2AoXv4QZH6ofsYFRShMBAg4WjzAgFp2NuZ2qEn+hCh1goMPEigAWRAT5g0fP2x8qAAfKByEE7dzyFhEFFQEHoJ0IEFkQXgSDQIJIpGutxEEWiVWSqTCym+ADN+vgnoF2pFMcRIOQJDppLJ5EplAAKAzcQgASlYNnMy2AhwKpHQZKkehCXB4fEEtLgePw3HQjO4YoCBT2kIBMJJ6BEhFUalULFZ5l17M5PHFADpPGozQKIDrTKYTJgCOCALY3cXceHiu7BeklKKxBKo2oCNx2-Dg9oPE5BAlEkg0pG+6poxk0p0nRnfHCYqA0qPEiCxn0omphJMp8WM5na3UWqBOxVoIERjQGZCZ0tylxQJpQPbh8UmUxAA
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.