如何将通用NGRX Action作为参数传入抽象CRUD服务?
实现基于NgRx Action的通用CRUD抽象服务
核心思路
通过TypeScript泛型+类型别名统一Action调用方式,将CRUD的通用逻辑封装在抽象类中,让具体实体组件仅需传入对应Action的包装函数即可复用逻辑。
步骤1:定义通用Action类型别名
先统一Add/Update/Delete Action的类型,适配不同实体Action的参数结构差异:
import { Action } from '@ngrx/store'; // 统一Add/Update Action的调用签名:接收实体T,返回NgRx Action type CRUDAction<T> = (entity: T) => Action; // Delete Action的调用签名:接收id,返回NgRx Action type DeleteAction = (id: number) => Action;
步骤2:完善抽象CRUD服务类
抽象类注入Store,通过构造函数接收Action包装函数,实现通用的save和delete逻辑:
import { Component, inject } from '@angular/core'; import { Store } from '@ngrx/store'; import { Action } from '@ngrx/store'; type CRUDAction<T> = (entity: T) => Action; type DeleteAction = (id: number) => Action; // 泛型约束确保实体必须包含id字段 @Component({ template: '' }) export abstract class CRUDService<T extends { id: number }> { // 抽象类直接注入Store,子类无需重复注入 protected readonly store = inject(Store); constructor( private addAction: CRUDAction<T>, private updateAction: CRUDAction<T>, private deleteAction: DeleteAction ) {} saveEntry = (entity: T) => { // 可在此添加通用验证、添加通用字段(如更新时间)等逻辑 const updatedEntity = { ...entity /* , updatedAt: new Date() */ }; // 根据id判断是新增还是更新 entity.id === 0 ? this.store.dispatch(this.addAction(updatedEntity)) : this.store.dispatch(this.updateAction(updatedEntity)); }; deleteEntry = (entity: T) => { this.store.dispatch(this.deleteAction(entity.id)); }; }
步骤3:具体实体组件继承抽象类
以Groups组件为例,传入对应Action的包装函数即可复用CRUD逻辑:
import { Component, inject } from '@angular/core'; import { FormBuilder } from '@angular/forms'; import { CRUDService } from './crud.service'; import { GroupModel } from './group.model'; import { GroupsActions } from './groups.actions'; @Component({ selector: 'app-crud-groups', template: `<!-- 具体组件模板 -->` }) export class CRUDGroupsComponent extends CRUDService<GroupModel> { // 子类注入自身需要的服务(如FormBuilder) private readonly fb = inject(FormBuilder); constructor() { // 传入适配后的Action包装函数,统一成抽象类需要的调用签名 super( (group) => GroupsActions.addGroup({ group }), (group) => GroupsActions.updateGroup({ group }), (id) => GroupsActions.removeGroup({ id }) ); } }
Shapes和Colors组件的实现逻辑完全一致,只需替换对应的Action和实体类型即可。
内容的提问来源于stack exchange,提问作者Starfish
相关产品推荐
相关产品推荐

