Redux Toolkit reducer泛型键类型问题:Type 'keyof T'无法索引Draft<T>
解决Redux Toolkit复用Reducer时的类型错误问题
你遇到的Type 'keyof T' cannot be used to index type 'Draft<T>'错误,核心原因是泛型T没有明确的结构约束,TypeScript无法确认keyof T对应的属性具备status、requestId等字段,同时Immer的Draft<T>包装类型也无法自动推导索引后的属性类型。
正确的类型标注方案
通过给泛型添加结构约束,让TypeScript明确知道状态对象的每个键对应的属性结构,就能解决类型错误:
- 先明确基础状态结构(你已定义
BaseSchema,这里补充完整类型约束):
interface BaseSchema { requestId: string; status: 'idle' | 'loading' | 'succeeded' | 'failed'; error: unknown | undefined; data: null | any; }
- 调整参数类型和工具函数的泛型约束:
// 修改参数类型,约束T为所有属性都是BaseSchema的对象 export type AsyncThunkPendingArgs<T extends Record<string, BaseSchema>, K> = { builder: ActionReducerMapBuilder<T>; thunk: AsyncThunk<AxiosResponse, K, Record<string, never>>; key: keyof T; }; // 工具函数添加泛型约束,让TypeScript能推导属性类型 export const createPendingData = <T extends Record<string, BaseSchema>, K>( args: AsyncThunkPendingArgs<T, K> ) => { args.builder.addCase(args.thunk.pending, (state, action) => { const targetState = state[args.key]; if (targetState.status !== 'loading') { targetState.requestId = action.meta.requestId; targetState.status = 'loading'; } }); };
- 调用方式保持不变即可:
export const extraReducers = (builder: ActionReducerMapBuilder<Schema>): void => { createPendingData<Schema, GetParams>({ builder, thunk: getThunk, key: 'events', }); };
其他复用思路
如果需要更灵活的复用形式,也可以直接将键作为泛型参数传入,同时通过类型断言确保属性结构(但不如泛型约束安全,仅适合临时场景):
export const createPendingData = <T, K extends keyof T>( builder: ActionReducerMapBuilder<T>, thunk: AsyncThunk<AxiosResponse, any, Record<string, never>>, key: K ) => { builder.addCase(thunk.pending, (state, action) => { const targetState = state[key] as Draft<BaseSchema>; if (targetState.status !== 'loading') { targetState.requestId = action.meta.requestId; targetState.status = 'loading'; } }); }; // 调用示例 createPendingData(builder, getThunk, 'events');
核心原理
通过T extends Record<string, BaseSchema>约束泛型T,TypeScript就能确定:
keyof T对应的每个属性都是BaseSchema类型Draft<T>[keyof T]等价于Draft<BaseSchema>,可以安全访问status、requestId等字段
内容的提问来源于stack exchange,提问作者Front user32
相关产品推荐
相关产品推荐

