【发布时间】:2018-03-28 19:08:50
【问题描述】:
在我的 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 没有文字类型。所以在 switch 案例中,TypeScript 不允许我访问action.brand。我也不能使用类型保护,因为我的操作中没有判别属性。有没有办法在不维护类型的字符串文字列表的情况下实现这一点?
[编辑] - 结果证明这种方法被严重误导,因为它会在为一种车辆类型调度操作时将所有车辆的 fetching 状态设置为 true。我想我对这样一个事实感到困惑:state 在被传递到减速器之前被缩小,所有 动作都通过它。但是,在极少数 (?) 情况下,我将把它留给后代,您需要在单个减速器中监听满足特定条件的所有操作。
在这种情况下,解决方案是使用类型保护,从而得到接受的答案。
【问题讨论】:
-
为什么
vehicle是动作类型的一部分?在我看来,这应该是动作有效负载的一部分。 -
我正在使用 redux-saga,如果我一个接一个地调度两个动作(一个用于
cars,一个用于buses),具有相同的动作类型会导致不必要的取消。同时,我想要如果在前一个相同车辆类型的传奇尚未结束之前调度了一种车辆类型的操作,则取消。 -
为什么不能使用类型保护?像这样:
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::"); } -
我试过了,但它似乎不起作用 - 动作被键入到类型保护之外的
never,这表明它匹配所有动作,但我可能忽略了一些东西。 -
@TitianCernicova-Dragomir 这似乎有效,我之前一定做错了什么。很高兴接受此评论的格式化版本。
标签: typescript redux