使用NgRx的store.select调用selectAllBookings时出现类型错误
解决NgRx中
store.select(selectAllBookings)的类型错误 执行代码public allBookings = this.store.select(selectAllBookings);时出现如下类型错误:
Overload 1 of 9, '(mapFn: (state: object) => Booking[]): Observable<Booking[]>', gave the following error. Argument of type 'MemoizedSelector<AppState, Booking[], (s1: BookingState) => Booking[]>' is not assignable to parameter of type '(state: object) => Booking[]'. Types of parameters 'state' and 'state' are incompatible. Property 'bookings' is missing in type '{}' but required in type 'AppState'. Overload 2 of 9, '(key: never): Observable<never>', gave the following error. Argument of type 'MemoizedSelector<AppState, Booking[], (s1: BookingState) => Booking[]>' is not assignable to parameter of type 'never'. [plugin angular-compiler] src/app/booking-table/booking-table.component.ts:14:41: 14 │ public allBookings = this.store.select(selectAllBookings); ╵ ~~~~~~~~~~~~~~~~~ 'bookings' is declared here. src/app/store/app.state.ts:4:4: 4 │ bookings: BookingState;
相关代码文件
AppState.ts
import { BookingState } from "./booking.reducer"; export interface AppState { bookings: BookingState; }
booking.action.ts
import { createAction, props } from "@ngrx/store"; import { Booking } from "../model/booking.model"; export const loadBookings = createAction( '[Booking API] Load bookings' ); export const loadBookingsSuccess = createAction( '[Booking API] Booking Load Success', props<{ bookings: Booking[] }>() );
booking.effects.ts
import { Injectable } from "@angular/core"; import { createEffect, ofType, Actions } from "@ngrx/effects"; import { map, switchMap, from } from "rxjs"; import { BookingService } from "../booking.service"; import * as BookingActions from "../store/booking.actions"; import { Store } from "@ngrx/store"; import { AppState } from "./app.state"; @Injectable() export class BookingEffects { constructor(private actions$: Actions, private bookingService: BookingService, private store: Store<AppState>) {} loadBookings$ = createEffect(() => this.actions$.pipe( ofType(BookingActions.loadBookings), switchMap(() => from(this.bookingService.getBookings()).pipe( map((bookings) => BookingActions.loadBookingsSuccess({ bookings: bookings})) ) ) ) ) }
booking.reducer.ts
import { createReducer, on } from "@ngrx/store"; import { Booking } from "../model/booking.model"; import { loadBookings, loadBookingsSuccess } from "./booking.actions"; export interface BookingState { bookings: Booking[]; error: string; status: 'pending' | 'loading' | 'error' | 'success'; } export const initialState: BookingState = { bookings: [], error: "", status: 'pending', } export const bookingReducer = createReducer( //Supply initial state initialState, //Trigger loading bookings on(loadBookings, (state) => ({ ...state, status: 'loading' as const })), on(loadBookingsSuccess, (state, { bookings }) => ({ ...state, bookings: bookings, error: '', status: 'success' as const, })) )
booking.selector.ts
import { createSelector } from "@ngrx/store"; import { AppState } from "./app.state"; import { BookingState } from "./booking.reducer"; export const selectBookings = (state: AppState) => state.bookings; export const selectAllBookings = createSelector( selectBookings, (state: BookingState) => state.bookings );
app.modules.ts
import { NgModule, isDevMode } from '@angular/core'; import { BrowserModule } from '@angular/platform-browser'; import { AppRoutingModule } from './app-routing.module'; import { AppComponent } from './app.component'; import { StoreModule } from '@ngrx/store'; import { StoreDevtoolsModule } from '@ngrx/store-devtools'; import { EffectsModule } from '@ngrx/effects'; import { BookingTableComponent } from './booking-table/booking-table.component'; import { provideAnimationsAsync } from '@angular/platform-browser/animations/async'; import { HttpClientModule } from '@angular/common/http'; import { bookingReducer } from './store/booking.reducer'; import { BookingEffects } from './store/booking.effects'; @NgModule({ declarations: [ AppComponent, BookingTableComponent ], imports: [ BrowserModule, AppRoutingModule, StoreModule.forRoot({ bookings: bookingReducer }, {}), StoreDevtoolsModule.instrument({ maxAge: 25, logOnly: !isDevMode() }), EffectsModule.forRoot([BookingEffects]), HttpClientModule ], providers: [ provideAnimationsAsync() ], bootstrap: [AppComponent] }) export class AppModule { }
booking.component.ts
import { Component, OnInit } from '@angular/core'; import { BookingService } from '../booking.service'; import { loadBookings } from '../store/booking.actions'; import { Store } from '@ngrx/store'; import { Booking } from '../model/booking.model'; import { selectAllBookings } from '../store/booking.selector'; @Component({ selector: 'app-booking-table', templateUrl: './booking-table.component.html', styleUrl: './booking-table.component.css' }) export class BookingTableComponent implements OnInit { //Error here public allBookings = this.store.select(selectAllBookings); constructor(private store: Store) { } ngOnInit(): void { this.store.dispatch(loadBookings()); } }
解决方案
错误原因是组件中注入的Store未指定泛型类型AppState,TypeScript无法识别全局状态的结构,导致与选择器的类型不匹配。
修改booking.component.ts:
- 导入
AppState接口 - 在构造函数中给
Store指定泛型<AppState>
修改后的代码:
import { Component, OnInit } from '@angular/core'; import { loadBookings } from '../store/booking.actions'; import { Store } from '@ngrx/store'; import { Booking } from '../model/booking.model'; import { selectAllBookings } from '../store/booking.selector'; // 新增导入 import { AppState } from '../store/app.state'; @Component({ selector: 'app-booking-table', templateUrl: './booking-table.component.html', styleUrl: './booking-table.component.css' }) export class BookingTableComponent implements OnInit { public allBookings = this.store.select(selectAllBookings); // 指定Store泛型为AppState constructor(private store: Store<AppState>) { } ngOnInit(): void { this.store.dispatch(loadBookings()); } }
修改后TypeScript可正确识别全局状态结构,选择器与store类型匹配,错误即可消除。
内容的提问来源于stack exchange,提问作者Strugglingperson
相关产品推荐
相关产品推荐

