Typescript 我如何重构/抽象ngrx操作以减少打字错误?

Typescript 我如何重构/抽象ngrx操作以减少打字错误?,typescript,redux,refactoring,action,ngrx,Typescript,Redux,Refactoring,Action,Ngrx,更新: 似乎typescript fsa可能是我正在寻找的固执己见的库。关于实现细节的任何帮助都将非常棒 我觉得当我这样做的时候,我总是在复制和粘贴文件,然后只是重命名部分。我很容易犯典型的胖手指错误。虽然我目前没有测试我的项目,但如果一个项目需要100%的代码覆盖率,那么这可能是一项更加乏味的任务 称为计数器的简单操作示例: import { Action } from '@ngrx/store'; export const INCREMENT = '[Counter] Increment

更新: 似乎typescript fsa可能是我正在寻找的固执己见的库。关于实现细节的任何帮助都将非常棒

我觉得当我这样做的时候,我总是在复制和粘贴文件,然后只是重命名部分。我很容易犯典型的胖手指错误。虽然我目前没有测试我的项目,但如果一个项目需要100%的代码覆盖率,那么这可能是一项更加乏味的任务

称为计数器的简单操作示例:

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('Animal',['Add','Remove','Reset'])

注意:这是一个人为的函数签名,因为它没有考虑有效负载及其类型,只是举个例子

但该函数可以生成/表示/工作如下:

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

最后,请不要思考,因为这不是一个好的解决方案。此外,“这是不可能的”也可能是一个可接受的答案…

一点点升级建议

import { Action } from '@ngrx/store';
import { Animal } from 'animal.models';

export const ADD = '[Auth] Add';

export class Add implements Action {
  readonly type = ADD;
  constructor(public payload: Animal[]) {}
}
我想用crud异步操作来实现更好、更灵活的NGRX/redux/flux方式,这是我第一次感到害怕,我使用阿波罗团队用同步选项做的内部异步存储,我认为这是一个未来,很好地管理选项,有一个真正的来源,他们为crud*操作创建了通用的操作机制,当你想做一些特别的事情时,你可以使用DI并编写带有不可变函数的存储缩减器,或者我认为你可以使用effects(我从来没有尝试过)

为什么我认为这是一个未来? apollo 2.0不需要重复CRUD操作的代码,每次在plus模式中捕获异步服务器操作的write effects都会通过对ts(生成器已准备好生产)的内省来保护您的类型,我对(James Baxley III编写的)和“未来功能”段落非常乐观-
当这个未来成为现在,服务器、浏览器、p2p live之间的一个存储和同步状态将是惊人的…

另一个解决方案是使用像*

因此,您可以定义动作生成器,而不是“本机”NgRx动作类,例如

最后,在你的影响

@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的代码编辑器中进行函数替换

如果您的操作在集合之间是同质的,即每个集合都有相同的“添加”、“删除”、“重置”等操作(但有不同的“集合”前缀;并且不是每个集合都必须实现所有这些操作),那么您可以更进一步,创建通用操作生成器、通用还原生成器、,等等,这样您就不必重复相同的代码多次

编辑:根据Matthew的要求,这是一个更高级的示例,它包含了泛型和NgRX实体**

*我不是那个软件包的作者


**我是这个例子的作者。在这里粘贴完整的示例有点笨拙(并且超出了问题的重点),但是如果共享该链接不合适,请务必告诉我。

ahh是的,这肯定会使键入更好。但仍然无法帮助解决它的冗长程度:(我没有使用它们,但是使用了新的entity软件包。它与fsa配合得好吗?如果可以,请您将其添加到问题中好吗?是的,它不知道在哪里添加它,但您可以更具体一些吗?顺便说一句,我发布了完整的代码,所以如果您需要完整的示例,请告诉我(不确定链接到这里是否合适)。实体包只是简化了样板文件。除此之外,我对它没有太多的了解。如果我的简单示例不能真正利用实体,那么我们就把它忽略掉。另外,如果你有活代码,只需更新问题..比如“这里有一个更可靠的回购协议可供学习。我认为ppl会很欣赏这一点。不仅是你,ngrx/store的正确实现是非常重复的,我在一个包上做了一些工作来减少这一点,但它增加了额外的复杂性。最好的办法是拥有多个action/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 => ...)