简体   繁体   English

编写自定义 ngrx 运算符并返回源 observable 类型

[英]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 ExtractofType 来源看来,我需要使用Extract

Update更新

StackBlitz example is shown here StackBlitz 示例显示在这里

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!遇到这个问题,我想我会添加一些解释,以防您仍然想知道将来是否有人遇到这个问题!

First - in your example you're overthinking it in terms of the return type.首先 - 在您的示例中,您在返回类型方面过度考虑了它。

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> - 同样的东西,同样的东西。

Second - how does ofType work?第二 - ofType 是如何工作的?

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'>;

验证 NarrowedActionTest 在 TS 操场上有效

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的类型签名。

  • NarrowActionType needs the overall action type as it's first type parameter, which we will call A NarrowActionType 需要整体动作类型作为它的第一个类型参数,我们将其称为A
  • NarrowActionType needs the string literal type which we are using to narrow with, which we will call T NarrowActionType 需要我们用来缩小范围的字符串文字类型,我们将其称为T
  • T is going to be a string, so T extends string T 将是一个字符串,所以T扩展了字符串
  • We only know the type of 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 application我们只知道T的类型开始,然后A的类型一旦 object stream 被应用,所以让我们在每个 function 应用程序中使用一个通用参数
  • The function is going to ultimately check if A.type is the same as type. function 将最终检查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.

相关问题 访问ngrx Observable中的变量总是返回未定义 - Accessing a variable in an ngrx Observable always returning undefined 使自定义运算符具有可观察性 - Make Custom operator with observable RxJS groupBy 对可观察自定义数组的 ngrx 效果 - RxJS groupBy on ngrx effects to observable custom array NgRX 效果 - 类型“Observable”<unknown> &#39; 不可分配给类型 &#39;Observable<Action> &#39; - NgRX effects - Type 'Observable<unknown>' is not assignable to type 'Observable<Action>' NGRX效果“ rxjs减速器运算符”停止了可观察的链 - NGRX Effect “rxjs reducer operator” stop the observable chain “MyModel”类型缺少“Observable”类型的以下属性<mymodel> ': Angular 中的 _isScalar、source、operator、lift 等 6 个</mymodel> - Type 'MyModel' is missing the following properties from type 'Observable<MyModel>': _isScalar, source, operator, lift, and 6 more in Angular 类型 X 缺少类型“Observable”中的以下属性<X> &#39;: _isScalar, source, operator, lift, 和 6 更多 - Type X is missing the following properties from type 'Observable<X>': _isScalar, source, operator, lift, and 6 more “订阅”类型缺少“可观察”类型的以下属性<any> ': _isScalar, source, operator, lift, and 6 more</any> - Type 'Subscription' is missing the following properties from type 'Observable<any>': _isScalar, source, operator, lift, and 6 more Ngrx,Rxjs-合并可观察流并返回新流 - Ngrx, Rxjs - Merging observable streams returning a new stream 在@ngrx/store@13.0.2 中选择reducer 返回Observable Store object - Selecting reducer in @ngrx/store@13.0.2 returning Observable Store object
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM