错误:使用TypeScript强制转换函数时,react-hooks/exhaustive-deps误报

axr492tv  于 2022-10-28  发布在  React
关注(0)|答案(4)|浏览(199)

React版本:17.0.1

重现步骤

使用@typescript-eslint/parser作为解析器来设置eslint
转换传递给useEffect的函数

import {useCallback, useEffect} from 'react';

type F = (...args: unknown[]) => void;

function MyComp() {
	const foo = useCallback(() => {}, []);

	// OK
	useEffect(() => {
		foo();
	}, [foo]);

	// WARNS?
	useEffect((() => {
		foo();
	}) as F, [foo]);

	return 'Hello, world'
}

链接到代码示例:https://github.com/0x24a537r9/exhaustive-deps-bug的最大值

当前行为

报告了以下错误

14:2  warning  React Hook useEffect received a function whose dependencies are unknown. Pass an inline function instead

预期行为

该规则应正确解释函数参数,并知道它已内联。

xlpyo6sf

xlpyo6sf1#

它看起来似乎很容易支持,但问题是:你为什么要这么做?

rdrgkggo

rdrgkggo2#

呵呵,一个公平的问题。在我的例子中,我需要它来支持一个钩子的泛型,这个钩子可以帮助管理异步调用的状态,比如突变:

export function useAsyncAction<F extends (...args: unknown[]) => Promise<R>, R>(
  doAction: F,
): [
  doActionWithState: F,
  isDoingAction: boolean,
  errorDoingAction: unknown | null,
  clearErrorDoingAction: () => void,
] {
  const [isDoingAction, setIsDoingAction] = useState<boolean>(false);
  const [errorDoingAction, setErrorDoingAction] = useState<unknown | null>(null);

  // https://github.com/facebook/react/issues/20750
  // eslint-disable-next-line react-hooks/exhaustive-deps
  const doActionWithState = useCallback(
    (async (...args: unknown[]): Promise<R> => {
      setIsDoingAction((prevIsDoingAction) => {
        if (prevIsDoingAction) {
          throw new ReentrancyError(doAction);
        }
        return true;
      });
      setErrorDoingAction(null);

      try {
        return await doAction(...args);
      } catch (e: unknown) {
        setErrorDoingAction(e);
        throw e;
      } finally {
        setIsDoingAction(false);
      }
    }) as F,
    [doAction],
  );

  const clearErrorDoingAction = useCallback(() => setErrorDoingAction(null), []);

  return [doActionWithState, isDoingAction, errorDoingAction, clearErrorDoingAction];
}

如果没有强制转换,TS就不知道args对象的形状是相同的。在return语句中,TS警告:

Type '(...args: unknown[]) => Promise<R>' is not assignable to type 'F'.
  '(...args: unknown[]) => Promise<R>' is assignable to the constraint of type 'F', but 'F' could be instantiated with a different subtype of constraint '(...args: unknown[]) => Promise<R>'.ts(2322)

即使我把args也变成泛型类型,这仍然是正确的,所以我认为这个问题是不可避免的。

exdqitrt

exdqitrt3#

@0x24a537r9 TS在此处是正确的。与F具有相同输入类型和返回类型的函数不能赋值给FF可能还附加了其他属性,这些属性不会附加到doActionWithState
对于您的特定情况,doActionWithState的类型可以是与F具有相同参数和返回类型的函数,但不应该是F。将其转换为F是对typescript撒谎。

xxslljrj

xxslljrj4#

啊。谢谢@Shrugsy!有了这个提示,我就能修复我的类型并消除演员阵容。
也就是说,我建议保持这个问题的开放性,因为总是会有一些情况,人们将不得不求助于这样的强制转换,无论是由于TS的表达能力的限制,还是(在这个例子中,我怀疑大多数情况下)人们理解类型复杂性和正确指定类型的能力的限制。遗憾的是,当类型变得复杂时,并不是每个人都可以访问@Shrugsy来帮助他们。

相关问题