在Redux中键入通用操作

时间:2018-03-27 10:53:44

标签: typescript redux

在我的redux商店中,我有许多几乎相同的状态切片:

{
  cars: { fetching: false, data: [], error: '' },
  buses: { fetching: false, data: [], error: '' },
  bicycles: { fetching: false, data: [], error: '' }
}

我希望采取以下行动:

const requestCars = {
  type: 'REQUEST::cars',
  brand: 'Toyota'
}

const errorBuses = {
  type: 'ERROR::buses',
  error: 'An error'
}

我可以生成操作,而不是明确声明每个操作:

const requestAction = (vehicle: string) => ({
  type: `REQUEST::${vehicle}`
})

我的减速机看起来像:

const makeReducer = (vehicle: string) => (state, action) => {

  // I want to capture any action that has type REQUEST:vehicle

  switch(action.type) {
    case // problem is here
  }
}

所以我的根减速器是:

{
  cars: makeReducer('cars'),
  buses: makeReducer('buses'),
  bicycles: makeReducer('bicycles')
}

所以在makeReducer(vehicle)中,我实际上需要不加选择地捕获REQUEST::${vehicle}类型的所有操作(例如将fetching设置为true)。

规范示例是使用标记的联合类型,但我不能,因为action.type没有文字类型。因此,在切换案例中,TypeScript不允许我访问action.brand。我也不能使用类型防护,因为我的行动中没有判别属性。有没有办法在不维护类型的字符串文字列表的情况下实现这一点?

[编辑] - 事实证明这种方法被严重误导,因为在为一种车型调度动作时,它会将所有车辆的fetching状态设置为true。我想我混淆了这样一个事实:state在被传递到reducer之前被缩小了,所有动作都通过它传递。但是,我会在罕见的(?)情况下为后代留下这个,你需要在一个减速器中听取满足特定条件的所有动作。

在这种情况下,解决方案是使用类型防护,从而接受答案。

2 个答案:

答案 0 :(得分:0)

为什么不让你的makeReducer函数采用更复杂的对象,而不仅仅是车辆类型名称?

carType = {
   name: 'car',
   requestType : requestAction('car').type
}

然后:

makeReducer(carType)

然后

const makeReducer = (vehicleType) => (state, action) => {
  switch(action.type) {
    case vehicleType.requestType:
        //do your thing
  }
}

答案 1 :(得分:0)

由于type不是字符串常量,因此您无法使用带标记的联合,因为它们的类型保护行为依赖于字符串文字类型。

但是,您可以使用自定义类型防护来检查操作是否是请求:

const makeReducer = (vehicle: string) => (state: any, action: {type: string}) => 
{ 
    if(isRequest(action)){ 
        console.log(action.brand); 
    } 
} 
function isRequest(action: {type: string}) : action is { type: string, brand: string } 
{ 
    return action.type.startsWith("REQUEST::"); 
}