我只想编写一个操作来对状态执行相同的 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 重现这一点那就太好了。