You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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明确知道状态对象的每个键对应的属性结构,就能解决类型错误:

  1. 先明确基础状态结构(你已定义BaseSchema,这里补充完整类型约束):
interface BaseSchema {
  requestId: string;
  status: 'idle' | 'loading' | 'succeeded' | 'failed';
  error: unknown | undefined;
  data: null | any;
}
  1. 调整参数类型和工具函数的泛型约束:
// 修改参数类型,约束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';
    }
  });
};
  1. 调用方式保持不变即可:
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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.26 08:42:48