React Context中setJobData函数式更新触发TypeScript类型错误
排查React Context中setJobData函数式更新的TypeScript类型错误
问题场景
调用setJobData进行函数式更新时触发TypeScript类型错误,核心代码及错误信息如下:
核心代码
const { jobData, setJobData } = useJobCreation(); const handleSkillSelect = (skillKey: string) => { const skillIndex = jobData.skillSet.findIndex( skill => skill.key === skillKey, ); if (skillIndex !== -1) { // 移除已选中的技能 const updatedSkillSet = jobData.skillSet.filter( skill => skill.key !== skillKey, ); setJobData((prevJobData: JobCreationType) => ({ ...prevJobData, skillSet: updatedSkillSet, })); } else { // 添加未选中的技能 const selectedSkill = filteredSkillsData.find( skill => skill.key === skillKey, ); if (selectedSkill) { setJobData((prevJobData: JobCreationType) => ({ ...prevJobData, skillSet: [...prevJobData.skillSet, selectedSkill], })); } } };
触发的错误信息
Argument of type '(prevJobData: JobCreationType) => { skillSet: Skill[]; jobRequirements: string[]; customRequirements: CustomRequirement[]; jobDetails: JobDetails; }' is not assignable to parameter of type 'JobCreationType'.
简化测试代码的错误
执行setJobData(prevJobData => ({ ...prevJobData }))时,同样报错:
Parameter 'prevJobData' implicitly has an 'any' type.ts(7006) Argument of type '(prevJobData: any) => any' is not assignable to parameter of type 'JobCreationType'.
相关类型定义
export interface JobCreationType { skillSet: Skill[]; jobRequirements: string[]; customRequirements: CustomRequirement[]; jobDetails: JobDetails; }
错误原因
问题根源在于useJobCreation返回的setJobData类型定义错误——它仅被定义为接受JobCreationType类型的直接值,不支持函数式更新的签名。
React原生状态更新函数(如useState返回的setter)支持两种调用形式:
- 直接传入新状态值:
setState(newValue) - 传入接收前状态的函数:
setState(prev => newState)
但你的Context中setJobData的类型未包含第二种形式,导致TypeScript判定传入的函数不符合参数要求。
解决方案
修正useJobCreation所在Context的类型定义,让setJobData同时支持两种更新方式:
步骤1:定义正确的setter类型
将setJobData的类型设置为React内置的React.Dispatch<React.SetStateAction<JobCreationType>>,该类型天然兼容两种更新形式:
// Context类型定义 interface JobCreationContextType { jobData: JobCreationType; setJobData: React.Dispatch<React.SetStateAction<JobCreationType>>; } // 创建Context并指定类型 const JobCreationContext = createContext<JobCreationContextType>({ jobData: { skillSet: [], jobRequirements: [], customRequirements: [], jobDetails: {} as JobDetails // 根据实际场景设置初始值 }, setJobData: () => {} // 空占位符 });
步骤2:在Provider中传递正确的setter
确保Provider中setJobData是useState返回的原生setter(或符合该类型的自定义函数):
export const JobCreationProvider = ({ children }: { children: React.ReactNode }) => { const [jobData, setJobData] = useState<JobCreationType>({ skillSet: [], jobRequirements: [], customRequirements: [], jobDetails: {} as JobDetails }); return ( <JobCreationContext.Provider value={{ jobData, setJobData }}> {children} </JobCreationContext.Provider> ); }; // 自定义hook定义 export const useJobCreation = () => useContext(JobCreationContext);
步骤3:简化调用代码(可选)
修正类型后,无需手动指定prevJobData的类型,TypeScript会自动推导:
// 移除手动指定的类型,代码更简洁 setJobData(prev => ({ ...prev, skillSet: updatedSkillSet, }));
验证
完成上述修改后,直接传值和函数式更新两种方式都能被TypeScript正确识别,不会再抛出类型错误。
内容的提问来源于stack exchange,提问作者Mike S.
相关产品推荐
相关产品推荐

