TypeScript自定义useStateIfMounted Hook类型错误修复方案问询
解决useStateIfMounted自定义Hook的TypeScript类型标注问题
问题背景
自定义useStateIfMounted Hook用于避免组件卸载后执行setState引发的警告,功能逻辑正常,但TypeScript类型标注存在问题:调用返回的setState方法时,出现类型错误:
Not all constituents of type 'T | ((value: SetStateAction<T>) => void)' are callable. Type 'T' has no call signatures.
需求是让Hook返回的setState方法类型与React原生useState完全一致。
错误复现代码
原Hook代码
import { useCallback, useState, useRef, useEffect } from 'react'; export function useStateIfMounted<T>(initialState: T | (() => T)) { const [state, setState] = useState(initialState); const isMounted = useRef(false); useEffect(() => { isMounted.current = true; return () => { isMounted.current = false; }; }, []); const setStateIfMounted = useCallback( (value) => { if (isMounted.current) { setState(value); } }, [] ); return [state, setStateIfMounted]; }
使用示例
const [count, setCount] = useStateIfMounted(0); setCount(prev => prev + 1); // 此处触发类型错误
问题原因
TypeScript默认会将Hook返回的数组推断为联合类型数组(T | ((value: SetStateAction<T>) => void))[],而非明确的元组类型,导致调用setCount时无法正确识别其函数类型。
正确解决方案
通过明确指定Hook的返回元组类型,并复用React内置的Dispatch和SetStateAction类型,让返回的setState方法与原生类型完全对齐:
import { useCallback, useState, useRef, useEffect, SetStateAction, Dispatch } from 'react'; // 明确指定返回类型为元组:[状态值, 状态更新函数] export function useStateIfMounted<T>(initialState: T | (() => T)): [T, Dispatch<SetStateAction<T>>] { const [state, setState] = useState(initialState); const isMounted = useRef(false); useEffect(() => { isMounted.current = true; return () => { isMounted.current = false; }; }, []); // 给useCallback指定泛型,匹配原生setState的类型 const setStateIfMounted = useCallback<Dispatch<SetStateAction<T>>>( (value) => { if (isMounted.current) { setState(value); } }, [] ); return [state, setStateIfMounted]; }
关键修改点
- 导入React内置的
SetStateAction(描述状态更新值的类型)和Dispatch(描述状态更新函数的类型); - 给Hook函数添加返回类型标注
[T, Dispatch<SetStateAction<T>>],明确返回的是固定顺序的元组,而非联合类型数组; - 给
useCallback指定泛型参数Dispatch<SetStateAction<T>>,确保回调函数的类型与原生setState完全一致。
依赖与配置确认
- React版本:16.8+(支持Hooks)
- TypeScript版本:4.0+(支持React内置类型)
- tsconfig.json核心配置示例:
{ "compilerOptions": { "jsx": "react-jsx", "lib": ["DOM", "ES2020"], "module": "ESNext", "target": "ES2020", "strict": true, "esModuleInterop": true } }
内容的提问来源于stack exchange,提问作者benard-kong
相关产品推荐
相关产品推荐

