更新: 看起来 typescript-fsa 可能是我正在寻找的固执己见的库 https://github.com/aikoven/typescript-fsa/issues/40 。任何有关实现细节的帮助都会很棒!
我在做ngrx时的感觉,我不断地复制和粘贴文件,然后只是重命名各个部分。这很容易出现我典型的胖手指错误。虽然我目前没有测试我的项目,但如果项目需要 100% 的代码覆盖率,这可能是一项更加繁琐的任务。
名为 Counter 的简单操作示例:
import { Action } from '@ngrx/store';
export const INCREMENT = '[Counter] Increment';
export const DECREMENT = '[Counter] Decrement';
export const RESET = '[Counter] Reset';
export class Increment implements Action {
readonly type = INCREMENT;
}
export class Decrement implements Action {
readonly type = DECREMENT;
}
export class Reset implements Action {
readonly type = RESET;
constructor(public payload: number) {}
}
export type All
= Increment
| Decrement
| Reset;
问题:
在 typescript 中,是否有任何模式可以通过简单的函数调用来获取上面显示的这些类集的功能?
一个例子是:
TypeAction.create('动物', ['添加', '删除', '重置'])
注意:这是一个人为的函数签名,因为它没有考虑有效负载的类型,而只是举例?
但是这个函数可以像下面的代码一样生成/表示/工作:
import { Action } from '@ngrx/store';
export const ADD = '[Animal] Add';
export const REMOVE = '[Animal] Remove';
export const RESET = '[Animal] Reset';
export class Add implements Action {
readonly type = ADD;
}
export class Remove implements Action {
readonly type = REMOVE;
}
export class Reset implements Action {
readonly type = RESET;
constructor() {}
}
export type All
= Add
| Remove
| Reset
最后,请不要反射(reflection),因为这不是一个好的解决方案。另外,“这是不可能的”也可能是一个可以接受的答案......
最佳答案
另一个解决方案是使用类似 typescript-fsa 的 Action 生成器*
因此,您可以定义操作生成器,而不是“原生”NgRx 操作类,例如
import { actionCreatorFactory } from 'typescript-fsa';
const counter = actionCreatorFactory('counter');
export const counterIncrement = counter('INCREMENT');
export const counterDecrement = counter('DECREMENT');
export const counterReset = counter<number>('RESET');
生成的操作将被命名为“计数器/增量”等。
在你的 reducer 中使用它们,如下所示:
import { isType } from 'typescript-fsa';
export function counterReducer(state: CounterState = initialState, action: Action) {
if (isType(action, counterIncrement)) {
return { ...state, < your reduction here > };
}
if (isType(action, counterDecrement)) {
return { ...state, < your reduction here > };
}
if (isType(action, counterReset)) {
return { ...state, < your reduction here > };
}
return state;
};
并将它们发送为
store.dispatch(counterIncrement());
store.dispatch(counterDecrement());
store.dispatch(counterReset(42));
最后,在你的效果中
@Effect() counterIncrement$ = this.actions$
.filter(counterIncrement.match)
.map(action => ...)
@Effect() counterDecrement$ = this.actions$
.filter(counterDecrement.match)
.map(action => ...)
@Effect() counterReset$ = this.actions$
.filter(counterReset.match)
.map(action => action.payload)
.map(payload => ...)
正如您所看到的,除了初始定义之外,您永远不会使用容易出现拼写错误的操作字符串,而是导入类型化的操作生成器,这提供了额外的安全性,并且还可以在支持 typescript 的代码编辑器中进行函数替换。
如果您的操作在各个集合中同质,即每个集合具有相同“ADD”、“REMOVE”、“RESET”等操作(但不同的“collection”前缀;并不是每个集合都必须实现所有这些),那么您可以更进一步,创建通用 Action 生成器、通用 reducer 生成器等。因此您不必多次重复相同的代码。
编辑:根据马修的要求,here是一个更高级的示例,结合了泛型和 NgRX 实体**。
*不是该包的作者
**我是该示例的作者。将完整的示例粘贴到此处有点笨拙(超出了这个问题的重点),但如果共享该链接不合适,请告诉我。
关于typescript - 如何重构/抽象 ngrx 操作以减少出现拼写错误的可能性?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46823049/