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

TypeScript类型错误求助:string不可赋值给never等问题

解决狗狗领养筛选函数的TypeScript类型错误

问题根源

你的代码里TypeScript无法准确推断filterBy.current[filterTitle]的具体类型:

  1. 尝试给字段push(string)时,TS无法确定该字段是否为string[],因此抛出string无法赋值给never的错误。
  2. 赋值number[]时,TS认为目标字段可能是string[]或number[],要求赋值必须同时兼容两种类型,导致类型冲突。

核心问题是FilterBy和FilterTopics的类型定义不够明确,没有绑定每个筛选字段的具体值类型。

解决方案

1. 明确类型定义

先给FilterBy和FilterTopics定义精确的类型,绑定每个筛选字段的取值类型:

// 定义每个筛选字段的具体类型
type FilterBy = {
  sex: string[];
  ageRange: number[];
  sizeAndWeight: string[];
  breed: string[];
  otherAnimalsInTheHousehold: string[];
};

// 让FilterTopics严格对应FilterBy的键
type FilterTopics = keyof FilterBy;

2. 添加类型守卫,确保类型安全

创建类型守卫函数,帮助TS识别当前筛选字段是number[]类型还是string[]类型:

// 判断当前筛选字段是否为number数组类型
function isNumberArrayField(title: FilterTopics): title is 'ageRange' {
  return title === 'ageRange';
}

3. 修改筛选函数逻辑

更新setFilterAnswer函数,利用类型守卫做类型判断,同时注意给父组件的setFilter传递新对象(避免引用不变导致的不更新问题):

const filterBy = useRef<FilterBy>({ 
  sex: [], 
  ageRange: [], 
  sizeAndWeight: [], 
  breed: [], 
  otherAnimalsInTheHousehold: [] 
});

const setFilterAnswer = (answer: string | number[], filterTopic: string) => {
  const relevantSubject = filterSubjects.find(subject => subject.topic === filterTopic)!;
  // 断言filterTitle为合法的FilterTopics类型
  const { filterTitle } = relevantSubject as { filterTitle: FilterTopics };

  // 过滤非法的筛选字段
  if (!Object.keys(filterBy.current).includes(filterTitle)) return;

  if (typeof answer === 'string') {
    // 仅对string数组类型的字段执行push操作
    if (!isNumberArrayField(filterTitle)) {
      (filterBy.current[filterTitle] as string[]).push(answer);
    }
  } else {
    // 仅对number数组类型的字段执行赋值操作
    if (isNumberArrayField(filterTitle)) {
      filterBy.current[filterTitle] = answer;
    }
  }

  const filteredDogs = getFilteredDogs(filterBy.current);
  setDogs(filteredDogs);
  // 创建新对象传递给setFilter,确保父组件触发更新
  setFilter({ ...filterBy.current });
};

额外说明

  • 移除了不必要的filterSubjectsReplika复制,直接使用原数组查找即可。
  • 给setFilter传递{ ...filterBy.current }是因为useRef的current是可变引用,直接传递不会触发父组件的useState更新,必须创建新对象。

内容的提问来源于stack exchange,提问作者Eytan Silberberg

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.07 08:01:04