在Redux Toolkit中使用泛型参数createSlice reducer with prepare?

au9on6nz  于 2023-04-30  发布在  其他
关注(0)|答案(2)|浏览(146)

我试图在RTK中创建一个reducer,它接受两个共享泛型类型的参数。然而,似乎不可能在reducerprepare函数之间共享泛型类型。
这里有一个我正在努力实现的例子

type SetPayload<T> = {
    thingToBeSet: MyClass<T>;
    value: T;
}

export const mySlice = createSlice({
    name: 'mySlice',
    initialState,
    reducers: {
        myReducer: {
            reducer: (state, action: PayloadAction<SetPayload<any>>) => {
                // Modify state here
            },
            prepare: <T>(thingToBeSet: MyClass<T>, value: T) => {
                return {
                    payload: { thingToBeSet, value }
                }
            }
        }
    }
});

如上面的代码所示,我的prepare函数使用了一个泛型参数(因为thingToBeSet上某些属性的类型必须与value的类型匹配)。然而,这个类型参数不能用于reducer函数中的action类型-我尝试将其设置为any,这给出了以下错误:

The types of 'payload.thingToBeSet' are incompatible between these types.
        Type 'MyClass<never>' is not assignable to type 'MyClass<any>'.
          Type 'any' is not assignable to type 'never'

由于any不能转换为T-但是我如何在reducer和prepare函数之间共享T呢?
我想我想要的是以某种方式为myReducer对象创建一个通用的对象字面量,类似于这样(不幸的是不是有效的TS -这可能吗?):

myReducer: <T> {
    reducer: (state, action: PayloadAction<SetPayload<T>>) => {
        // Modify state here
    },
    prepare: (thingToBeSet: MyClass<T>, value: T) => {
        return {
            payload: { thingToBeSet, value }
        }
    }
}

任何帮助将不胜感激。

6tdlim6h

6tdlim6h1#

不幸的是,这是不可能的。这些类型在内部被Map以创建一个新的动作创建器函数-并且被Map的类型不能继承泛型功能。
最好的办法是在导出动作生成器之前将其强制转换为泛型函数类型。

export const myReducer = slice.actions.myReducer as <T>(thingToBeSet: MyClass<T>, value: T) => PayloadAction<SetPayload<T>>)
py49o6xq

py49o6xq2#

我使用的最终解决方案是在createSlice之外手动创建action,并为reducer使用extraReducers属性。设置函数的type属性允许自动键入和类似于RTK的用法。这是更详细和不理想的,但它至少给出了正确的类型,并在reducer中的隐式类型。
行动:

const myActionName = 'myAction';
export function myAction<T>(thingToBeSet: MyClass<T>, value: T): PayloadAction<SetPayload<T>> {
    return {
        type: myActionName,
        payload: { thingToBeSet, value }
    }
}
myAction.type = myActionName;

减速器:

createSlice({
    ...
    extraReducers: (builder) => {
        builder
            .addCase(myAction, (state, action) => {
                // Perform state changes
                // `state` and `action` have correct implicit types
                // (`action` is of type `PayloadAction<SetPayload<unknown>>`)
            })
    }
});

相关问题