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

在Redux中使用TypeScript类型定义时遇到WritableDraft错误

TypeScript类型错误解决:联合类型数组与对应属性数组的类型匹配问题

错误原因

TypeScript无法建立animalKey与对应动物类型的关联关系。当animalKey的类型是keyof Required<Foo>['animals'](即'dogs'|'cats'|'fishs')时,state.animals[animalKey]的类型会被推断为Dogs[] | Cats[] | Fishs[],而animal是Dogs|Cats|Fishs的联合类型。此时TypeScript会要求animal必须满足所有数组元素类型的交集(Dogs & Cats & Fishs),这显然无法实现,因此抛出类型不兼容错误。

解决方案

方案1:泛型关联Key与动物类型

通过泛型约束animalKey,让TypeScript明确知道当前key对应的动物类型,从而正确推断数组元素类型:

type AnimalMap = Required<Foo>['animals']

someFunction: <K extends keyof AnimalMap>(
  state, 
  action: PayloadAction<{ index: number, animalKey: K }>
) => {
  const { index, animalKey } = action.payload
  // 断言animal为当前key对应的动物类型
  const animal = state.animalQueue[index] as AnimalMap[K][number]
  state.animals[animalKey]!.push(animal)
}

方案2:类型守卫判断(繁琐但更安全)

如果需要严格的类型检查,可以定义类型守卫函数,手动判断animal的类型是否与animalKey匹配:

// 定义类型守卫函数,假设Dogs/Cats/Fishs有各自独有的属性
function isDog(animal: Dogs | Cats | Fishs): animal is Dogs {
  return 'breed' in animal
}

function isCat(animal: Dogs | Cats | Fishs): animal is Cats {
  return 'height' in animal
}

function isFish(animal: Dogs | Cats | Fishs): animal is Fishs {
  return 'waterType' in animal
}

someFunction: (state, action: PayloadAction<{ index: number, animalKey: keyof Required<Foo>['animals']}>) => {
  const { index, animalKey } = action.payload
  const animal = state.animalQueue[index]

  if (animalKey === 'dogs' && isDog(animal)) {
    state.animals.dogs!.push(animal)
  } else if (animalKey === 'cats' && isCat(animal)) {
    state.animals.cats!.push(animal)
  } else if (animalKey === 'fishs' && isFish(animal)) {
    state.animals.fishs!.push(animal)
  }
}

说明

你的animalQueue定义(Dogs | Cats | Fishs)[]本身是没问题的,它确实表示可以包含任意数量这三种类型元素的数组。问题出在TypeScript无法自动关联animalKey和对应的动物类型,需要通过泛型或类型守卫来明确这种关联。

内容的提问来源于stack exchange,提问作者four-eyes

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.13 17:22:47