javascript - NgRx createReducer() and on() is giving error - Stack Overflow

admin2025-04-10  0

I am new. to NgRx.

When I am trying to create reducer using createReducer() I am getting error Expected 4 arguments, but got 2. When I am trying to pass 3rd and 4th argument as null, I am getting error

Argument of type '(state: any, { updatedValue }: any) => any' is not assignable to parameter of type 'readonly ActionCreator<string, FunctionWithParametersType<any[], object>>[]'.
  Type '(state: any, { updatedValue }: any) => any' is missing the following properties from type 'readonly ActionCreator<string, FunctionWithParametersType<any[], object>>[]': concat, join, slice, indexOf, and 15 more.ts(2345)

Reducer code

import { createReducer, on, State, Action } from '@ngrx/store';

import { Ingredient } from '../../shared/ingredient.model';
import * as ShoppingListAction from './shopping-list.action';

export const initialState = {
  ingredients: [
    new Ingredient('Apples', 5),
    new Ingredient('Tomatoes', 10),
  ]
}

export const shoppingListReducer = createReducer(
  initialState,
  on(
    'ADD_INGREDIENT',
    (state: any, { updatedValue }: any) => ({ ...state, prop: updatedValue }),
    null,
    null
  )
);

actions code

import { createAction, props } from '@ngrx/store';
import { Ingredient } from '../../shared/ingredient.model';


export const ADD_INGREDIENT = 'ADD_INGREDIENT';

export const AddIngredient = createAction(
  ADD_INGREDIENT,
  props<Ingredient>()
);

app.module.ts

import { SharedModule } from './shared/shared.module';
import { CoreModule } from './core.module';
import { LoggingService } from './logging.service';

// Store
import { shoppingListReducer } from './shopping-list/store/shopping-list.reducer';

@NgModule({
  declarations: [AppComponent, HeaderComponent],
  imports: [
    BrowserModule,
    HttpClientModule,
    AppRoutingModule,
    SharedModule,
    CoreModule,
    StoreModule.forRoot({ 'slReduce': shoppingListReducer })
  ],
  bootstrap: [AppComponent],
  // providers: [LoggingService]
})
export class AppModule {}

package.json

"dependencies": {
    "@angular/animations": "^11.2.1",
    "@angular/mon": "^11.2.1",
    "@angular/piler": "^11.2.1",
    "@angular/core": "^11.2.1",
    "@angular/forms": "^11.2.1",
    "@angular/platform-browser": "^11.2.1",
    "@angular/platform-browser-dynamic": "^11.2.1",
    "@angular/router": "^11.2.1",
    "@ngrx/store": "^11.0.1",
    "bootstrap": "3.3.7",
    "core-js": "^3.1.2",
    "rxjs": "^6.0.0",
    "tslib": "^2.0.0",
    "zone.js": "~0.11.3"
  }

I am new. to NgRx.

When I am trying to create reducer using createReducer() I am getting error Expected 4 arguments, but got 2. When I am trying to pass 3rd and 4th argument as null, I am getting error

Argument of type '(state: any, { updatedValue }: any) => any' is not assignable to parameter of type 'readonly ActionCreator<string, FunctionWithParametersType<any[], object>>[]'.
  Type '(state: any, { updatedValue }: any) => any' is missing the following properties from type 'readonly ActionCreator<string, FunctionWithParametersType<any[], object>>[]': concat, join, slice, indexOf, and 15 more.ts(2345)

Reducer code

import { createReducer, on, State, Action } from '@ngrx/store';

import { Ingredient } from '../../shared/ingredient.model';
import * as ShoppingListAction from './shopping-list.action';

export const initialState = {
  ingredients: [
    new Ingredient('Apples', 5),
    new Ingredient('Tomatoes', 10),
  ]
}

export const shoppingListReducer = createReducer(
  initialState,
  on(
    'ADD_INGREDIENT',
    (state: any, { updatedValue }: any) => ({ ...state, prop: updatedValue }),
    null,
    null
  )
);

actions code

import { createAction, props } from '@ngrx/store';
import { Ingredient } from '../../shared/ingredient.model';


export const ADD_INGREDIENT = 'ADD_INGREDIENT';

export const AddIngredient = createAction(
  ADD_INGREDIENT,
  props<Ingredient>()
);

app.module.ts

import { SharedModule } from './shared/shared.module';
import { CoreModule } from './core.module';
import { LoggingService } from './logging.service';

// Store
import { shoppingListReducer } from './shopping-list/store/shopping-list.reducer';

@NgModule({
  declarations: [AppComponent, HeaderComponent],
  imports: [
    BrowserModule,
    HttpClientModule,
    AppRoutingModule,
    SharedModule,
    CoreModule,
    StoreModule.forRoot({ 'slReduce': shoppingListReducer })
  ],
  bootstrap: [AppComponent],
  // providers: [LoggingService]
})
export class AppModule {}

package.json

"dependencies": {
    "@angular/animations": "^11.2.1",
    "@angular/mon": "^11.2.1",
    "@angular/piler": "^11.2.1",
    "@angular/core": "^11.2.1",
    "@angular/forms": "^11.2.1",
    "@angular/platform-browser": "^11.2.1",
    "@angular/platform-browser-dynamic": "^11.2.1",
    "@angular/router": "^11.2.1",
    "@ngrx/store": "^11.0.1",
    "bootstrap": "3.3.7",
    "core-js": "^3.1.2",
    "rxjs": "^6.0.0",
    "tslib": "^2.0.0",
    "zone.js": "~0.11.3"
  }
Share Improve this question edited Feb 22, 2021 at 7:19 Piyush Jain asked Feb 22, 2021 at 6:12 Piyush JainPiyush Jain 1,9863 gold badges22 silver badges40 bronze badges
Add a ment  | 

3 Answers 3

Reset to default 4

I was seeing this error in my IDE, along with some other strange type-related errors with @ngrx/store, but the projects were piling just fine.

I had upgraded my typescript version in my projects that use @ngrx to the latest (v4.3.4 at the time), but my workspace included several other projects, and my IDE (I'm using WebStorm) typescript language service was configured to use an older version of typescript that was installed on one of my other projects. After configuring the IDE typescript service to use the newer typescript version, the errors went away.

So in my case, it was a couple different things - first, I needed to upgrade the typescript version for my projects that use @ngrx to work with some newer language features @ngrx is using. Then, I also had to make sure my IDE's typescript language service was using that version, or at least a fairly recent version of typescript to avoid seeing bogus errors in the editor windows.

Your action and your reducer look strange. According to the docs it should be something like:

export interface MyState {
    ingredients: Array<Ingredient>;
}

export const initialState: MyState = {
  ingredients: [
    new Ingredient('Apples', 5),
    new Ingredient('Tomatoes', 10),
  ]
}

// see  https://ngrx.io/guide/store/actions
// note: the prop has a 'name: Type', not just 'Type'
export const AddIngredient = createAction(
    ADD_INGREDIENT,
    props<{ingredient: Ingredient}>()
);

// verbose func to show difference
export const shoppingListReducer = createReducer(
  initialState,
  on(
    AddIngredient, // the action, not the action.type
    (state, { ingredient }) => {
      let ingredients = Array.from(state.ingredients);
      ingredients.push(ingredient);
      return { ingredients };
    }
  )
);

Or if you prefer the shorthand:

// equal shorthand function
export const shoppingListReducer = createReducer(
  initialState,
  on(
    AddIngredient, // the action, not the action.type
    (state, { ingredient }) => ({ingredients: [...state.ingredients, ingredient]})
  )
);

The main points are:

(state: any, { updatedValue }: any) => ({ ...state, prop: updatedValue })
  • would require an action with a prop named updatedValue (pare to action, prop now named ingredient)
  • returns an object assembled from the current state and a field called prop (*)

(*) If this worked, it would lead to a state like

interface MyAccidentalState {
  ingredients: Array<Ingredient>;
  prop: Ingredient;
}

... but it does not work, as your action has no named prop 'updatedValue' and prop: updatedValue was not {prop: updatedValue}.

And because it has no named prop 'updatedValue', the piler explodes at the object destructuring part of

(state: any, { updatedValue }: any) => ...

And the any-typing in (state: any, { updatedValue }: any) => ... may deny the piler some knowledge which was already there: updatedValue was intended to be an Ingredient, and state is (now) a MyState.

Side-note:

Keeping the state of a collection is something where ngrx/entity might be useful - but your way is valid, too.

Make sure you don't have a missmatch in the @ngrx/store library version and your installed @angular/core version.

Normally they should be on the same major version - for @angular/core ^9.x.x you should use a respective ^9.x.x version of @ngrx/store. This happened to me when I was on Angular 9 and installed the latest, stable ngrx version (which currently is 11.x.x).

Read more about the requirements (link refers to V9, but can apply for newer ones aswell): https://ngrx.io/guide/migration/v9

转载请注明原文地址:http://conceptsofalgorithm.com/Algorithm/1744275017a239204.html

最新回复(0)