可以通用化 NGXS 操作吗?

skw*_*wny 8 ngxs

我只想编写一个操作来对状态执行相同的 CRUD 操作,只是在状态的不同部分上执行,同时保持类型安全。

例如,我想使用以下操作将集合操作应用于具有泛型类型的任何切片T:

export class Set_Entity<T> {
  static readonly type = '[Entity] Set';
  constructor(public payload: <T>) {}
}
Run Code Online (Sandbox Code Playgroud)

这是有问题的,因为类型总是相同的。是否可以以某种方式装饰此类,以便type在将其用作 时可以传入唯一的属性@Action?

就像是:

/* action* /
class Set_Entity<T> {
  constructor(public entity: string, public payload: <T>) {}
}


/* state */
@Action(Set_Entity('[Groups] Set Group'/* <-- Changes the `type` property */))
set_group(
  context: StateContext<Model>, 
  action: SetEntity<{entity: string, payload: Group}>,
) {
  const entity = action.entity;
  const data = action.payload;
  context.patchState({ [entity]: data });
}


/* facade or something */
this.store.dispatch([
  new Set_Entity<GroupEntityType>(
    'user', // <-- the state slice
    aRecord,
  ),
]);


Run Code Online (Sandbox Code Playgroud)

即使这个解决方案还有更多不足之处。仍然必须为每个状态片、每个 CRUD 操作编写通用操作。如果能够对每个状态片上的每个 CRUD 操作使用相同的通用操作,那就太好了。

我通过typescript-fsa和typescript-fsa-reducers成功地使用 NGRX 完美地做到了这一点。整个状态只需要一个通用操作加上一个通用减速器,所有类型都是安全的。

动作是这样的:

function generic_set_action<T>(sliceName: string): ActionCreator<T> {
  const creator = actionCreatorFactory(sliceName);
  const action = creator<T>('set')
  return action; // Produces type of  `sliceName/set`
}

// Create the action
generic_set_action<User>('sliceName')(payload)
Run Code Online (Sandbox Code Playgroud)

减速机:

export function create_generic_reducer<T>(sliceName: string) {
  const action_set = generic_set_action<T>(sliceName);

  return reducerWithInitialState({} as T)
    .case(action_set, (state, data) => (data))
    .build();
}
Run Code Online (Sandbox Code Playgroud)

最后在创建减速器时:

export const Reducers: ActionReducerMap<State> = {
  coolSlice: create_generic_reducer<MySliceModel>('coolSlice'),
  // repeat for each slice..
};

Run Code Online (Sandbox Code Playgroud)

如果能够用 NGXS 重现这一点那就太好了。