在我的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之前被缩小了,所有动作都通过它传递。但是,我会在罕见的(?)情况下为后代留下这个,你需要在一个减速器中听取满足特定条件的所有动作。
在这种情况下,解决方案是使用类型防护,从而接受答案。
答案 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::");
}