完整错误:
Not all constituents of type 'T | ((value: SetStateAction<T>) => void)' are callable.
Type 'T' has no call signatures.
总结:
我正在尝试创建一个
useStateIfMounted
自定义挂钩。它工作得很好,但我似乎无法为 TypeScript 正确输入它。钩子很好,但是调用者在尝试调用 setState() 时收到错误。我应该如何输入 useCallback() 才能获得 TypeScript 良好的输入系统。 args 应该与 React 中的常规 setState 完全相同。
我的代码:
/**
* Same as useState, but the setState will not run if component is unmounted.
*
* The setState is safe to use in dependency arrays because useCallback() has empty dependencies.
*/
export function useStateIfMounted<T>(initialState: T | (() => T)) {
const componentUnmountedRef = useRef(false);
const [state, _setState] = useState<T>(initialState);
// TEMP: Line below will result in error if we don't type as 'any'
const setState: any = useCallback((value: SetStateAction<T>) => {
if (!componentUnmountedRef?.current) {
_setState(value);
}
}, [])
useEffect(() => {
return () => {
componentUnmountedRef.current = true;
}
}, [])
return [state, setState]
}
然后,当用户尝试调用
setState()
时,TypeScript 将显示错误。我能解决这个问题的唯一方法是暂时将回调 (useCallback) 设置为“任意”,但这并不能让我很好地输入允许作为参数输入的内容。请参阅下面的示例了解错误是如何发生的:
---REDACTED---
const [someState, setSomeState] = useState<CustomType>(null)
---REDACTED---
setSomeState(SomeCustomObject) // <-- This line displays TypeScript errors
我尝试过的:
const setState = useCallback((value: SetStateAction<T>) => { ... }
const setState: Dispatch<SetStateAction<T>> = useCallback((value: SetStateAction<T>) => { ... }
const setState = useCallback((value: T | ((prevState: T) => T) => { ... }
const setState = useCallback((value: any) => { ... }
<-- This one is curious as I would have expected TypeScript to allow me to pass 任何争论。免责声明:所有这些都是我自己的代码,但名称是我从this repo得到的。他们没有用 TypeScript 编写代码,所以我要求正确输入代码。我原来的名字是
useStateUnmountedAsync
,但我更喜欢他们的名字。我发现了几个其他自定义钩子,它们本质上是相同的想法,但没有一个是用 TypeScript 编写的。
编辑:添加我的 tsconfig.json 和版本 tsconfig.json
{
"compilerOptions": {
"baseUrl": "src",
"target": "es5",
"lib": [
"dom",
"dom.iterable",
"esnext"
],
"downlevelIteration": true,
"allowJs": true,
"skipLibCheck": true,
"esModuleInterop": true,
"allowSyntheticDefaultImports": true,
"strict": false,
"forceConsistentCasingInFileNames": true,
"noFallthroughCasesInSwitch": true,
"module": "esnext",
"moduleResolution": "node",
"resolveJsonModule": true,
"isolatedModules": true,
"noEmit": true,
"jsx": "react-jsx",
"allowUnreachableCode": true
},
"include": [
"src"
],
"exclude": [
"**/node_modules/**",
"build/**",
"public/**"
]
}
版本:
"react": "^17.0.1",
"react-scripts": "4.0.3",
"typescript": "^4.2.3",
"@typescript-eslint/eslint-plugin": "^4.22.0",
"@typescript-eslint/parser": "^4.22.0",
以元组形式输入返回值:
return [state, setState] as const;
您需要指定这一点,否则
state
和 setState
都是 boolean | ((value: React.SetStateAction<boolean>) => void)
类型,并且该联合中只有一部分是可调用的。元组确保状态位于索引 0,setter 位于索引 1。
这本质上是多余的,但要获得与
useState
相同的类型,您还可以考虑将 setState
显式键入为:
const setState: React.Dispatch<SetStateAction<T>>
明确指定 setter 函数的类型以及钩子的返回类型。
type SetValue<T> = Dispatch<SetStateAction<T>>;
export function useStateIfMounted<T>(initialState: T | (() => T)): [T, SetValue<T>] {
// code here
const setState: SetValue<T> = useCallback((value) => {
// code here
}
// code here
}