如何为Redux切片及动作创建强类型泛型函数?
问题描述
我正在使用@reduxjs/toolkit,希望创建一个可扩展的函数,用于生成带有默认reducer的Redux切片。当前实现可正常运行,但不具备强类型特性。如何创建该函数,使切片的actions类型既包含默认reducer,又包含传入的自定义reducer?我尝试过类型推断,但未成功实现。
最小示例
common.ts(切片共享逻辑)
export interface StoreState<T> { data: T status: 'succeeded' | 'failed' | 'idle' error: string | null } // 创建切片并支持扩展reducer,不止包含reset和updateStatus export const createStoreSlice = <T>(props: { sliceName: string defaultState: T reducers?: SliceCaseReducers<StoreState<T>> // <-- 希望在slices/<sliceName>.ts中推断此类型 }) => { const { sliceName, reducers, defaultState } = props const initialState: StoreState<T> = { data: defaultState, status: 'idle', error: null, } return createSlice({ name: sliceName, initialState, reducers: { ...reducers, // <--- 导出切片actions时希望能推断此类型 reset: (state) => { Object.assign(state, initialState) }, updateStatus: (state, action) => { state.status = action.payload }, }, }) }
slices/.ts(带额外逻辑的特定切片)
export const genericSlice = createStoreSlice({ sliceName: 'someSliceName', defaultState: { someField: 'some value' }, reducers: { setSomeField: (state, action) => { const { payload } = action state.data.someField = payload }, }, }) // 这些actions应从createStoreSlice参数获取强类型,包含默认reducer(如reset、updateStatus)和切片专属reducer(如setSomeField) export const { reset, updateStatus, setSomeField } = genericSlice.actions
解决方案
要实现强类型支持,需要让createStoreSlice正确推断自定义reducers的类型,并与默认reducers的类型合并。核心是通过泛型参数捕获自定义reducers类型,结合Redux Toolkit内置类型完成类型合并。
修改后的common.ts代码如下:
import { createSlice, SliceCaseReducers, Slice } from '@reduxjs/toolkit' export interface StoreState<T> { data: T status: 'succeeded' | 'failed' | 'idle' error: string | null } // 定义默认reducers的明确类型 type DefaultReducers<T> = { reset: (state: StoreState<T>) => void updateStatus: (state: StoreState<T>, action: { payload: StoreState<T>['status'] }) => void } // 添加泛型R捕获自定义reducers类型,默认值为空对象支持无自定义reducers场景 export const createStoreSlice = <T, R extends SliceCaseReducers<StoreState<T>> = {}>(props: { sliceName: string defaultState: T reducers?: R }): Slice<StoreState<T>, R & DefaultReducers<T>> => { const { sliceName, reducers, defaultState } = props const initialState: StoreState<T> = { data: defaultState, status: 'idle', error: null, } const defaultReducers: DefaultReducers<T> = { reset: (state) => { Object.assign(state, initialState) }, updateStatus: (state, action) => { state.status = action.payload }, } return createSlice({ name: sliceName, initialState, reducers: { ...reducers, ...defaultReducers, } as R & DefaultReducers<T>, // 类型断言确保合并后的reducers类型合法 }) }
关键说明
- 新增泛型参数
R用于捕获传入的自定义reducers类型,默认值设为空对象,兼容不传入自定义reducers的场景。 - 定义
DefaultReducers<T>明确默认reducers的参数和返回值类型,避免类型模糊。 - 返回类型指定为
Slice<StoreState<T>, R & DefaultReducers<T>>,让切片的actions自动合并自定义与默认reducers的类型。 - 通过
as R & DefaultReducers<T>进行类型断言,消除TypeScript对合并后reducers类型的校验报错。
修改后,在slices/<sliceName>.ts中,genericSlice.actions会自动包含reset、updateStatus和setSomeField的强类型,解构时不会出现类型错误,且每个action的payload类型也会被正确推断。
内容的提问来源于stack exchange,提问作者Edwin
相关产品推荐
相关产品推荐

