NgRx Effects 类型错误:使用ACTIONS常量后出现类型不匹配
解决NgRx动作常量替换后的类型不匹配错误
错误原因
将动作类型字符串替换成ACTIONS.PAGINATE_STUDENTS常量后,TypeScript无法通过字符串字面量推断出该动作的具体类型(包含pageSize和pageIndex属性)。原代码直接写字符串时,ofType能精准识别对应Action类型,但普通字符串常量会被识别为宽泛的string类型,导致ofType返回的流类型是通用Action,而非带payload的具体动作类型,最终和mergeMap里声明的动作类型不匹配。
解决方案
方案1:让ACTIONS常量保留字符串字面量类型
修改ACTIONS定义,添加as const让TypeScript将每个属性识别为字面量类型:
export const ACTIONS = { // ...其他动作 PAGINATE_STUDENTS: '[Student List] Paginate students', PAGINATE_STUDENTS_SUCCESS: '[Student List] Paginate students success' // ...其他动作 } as const;
同时补充创建PAGINATE_STUDENTS对应的动作创建函数(之前仅提供了成功动作的创建函数):
// student.action.ts export const paginateStudents = createAction( ACTIONS.PAGINATE_STUDENTS, props<{ pageSize: number; pageIndex: number }>() ); export const paginateStudentsSuccess = createAction( ACTIONS.PAGINATE_STUDENTS_SUCCESS, props<{ payload: { studentList: readonly Student[]; pageSize: number } }>() );
之后在effect中可以选择两种写法(推荐第二种,类型更安全):
// 写法A:用字面量类型的常量 paginateStudents$ = createEffect(() => this.actions$.pipe( ofType(ACTIONS.PAGINATE_STUDENTS), mergeMap((action) => this.studentService.getAll(action.pageSize, action.pageIndex) .pipe( map((students: StudentResponse) => paginateStudentsSuccess({ payload: { studentList: students.data, pageSize: students.pageSize } })), catchError(() => EMPTY) )) )); // 写法B:直接传入动作创建函数(类型推断更精准) paginateStudents$ = createEffect(() => this.actions$.pipe( ofType(paginateStudents), mergeMap((action) => this.studentService.getAll(action.pageSize, action.pageIndex) .pipe( map((students: StudentResponse) => paginateStudentsSuccess({ payload: { studentList: students.data, pageSize: students.pageSize } })), catchError(() => EMPTY) )) ));
方案2:手动指定ofType的泛型类型
如果不想修改ACTIONS定义,可手动给ofType指定动作的具体类型:
import { Action } from '@ngrx/store'; // 定义动作类型 type PaginateStudentsAction = Action & { pageSize: number; pageIndex: number }; paginateStudents$ = createEffect(() => this.actions$.pipe( ofType<PaginateStudentsAction>(ACTIONS.PAGINATE_STUDENTS), mergeMap((action) => this.studentService.getAll(action.pageSize, action.pageIndex) .pipe( map((students: StudentResponse) => ({ type: ACTIONS.PAGINATE_STUDENTS_SUCCESS, payload:{ studentList: students.data, pageSize: students.pageSize } })), catchError(() => EMPTY) )) ));
关键说明
- NgRx的
ofType传入动作创建函数时,会自动推断动作的具体类型,这是最安全的写法,避免手动类型断言出错。 - 用
as const修饰常量对象,能让TypeScript保留每个属性的字面量类型,确保类型推断的准确性。
内容的提问来源于stack exchange,提问作者Andrés Ucero
相关产品推荐
相关产品推荐

