为任何类型的 HTML 元素键入自定义 useRef 挂钩

kdi*_*zle 4 html ref typescript reactjs

我对 Typescript 还是有点陌生​​,我的目标是React.useRef在 Typescript 中创建一个返回引用的自定义钩子。我希望为任何 HTML 元素键入此引用,而不仅仅是按钮。我遇到了正确输入此自定义挂钩的问题。

这是我的钩子:

type CustomRefHook = (dependencies?: string | boolean | number[]) => React.MutableRefObject<HTMLButtonElement | null>;

const useCustomRefHook: CustomRefHook = (...dependencies) => {
  const ref = React.useRef<HTMLButtonElement | null>(null);

  useEffect(() => {
    // ... do stuff
  }, dependencies)

  return ref;
}
Run Code Online (Sandbox Code Playgroud)

目前,这个钩子的大部分用例都是按钮,但我希​​望最终将其扩展到任何类型的 HTML 元素。我尝试使用HTMLElement而不是HTMLButtonElement,但是我收到以下类型错误:

Type 'MutableRefObject<HTMLElement | null>' is not assignable to type 'string | ((instance: HTMLButtonElement | null) => void) | RefObject<HTMLButtonElement> | null | undefined'.
  Type 'MutableRefObject<HTMLElement | null>' is not assignable to type 'RefObject<HTMLButtonElement>'.
    Types of property 'current' are incompatible.
      Type 'HTMLElement | null' is not assignable to type 'HTMLButtonElement | null'.
Run Code Online (Sandbox Code Playgroud)

每当我尝试将此引用附加到按钮时。使用HTMLButtonElement可以消除 Typescript 错误,但我再次希望这个钩子能够处理任何类型的 HTML 元素。

Lin*_*ste 7

的类型ref需要与其附加的 DOM 元素完全匹配,因此您需要使用泛型来指定元素类型。

由于useCustomRefHook现在是一个通用函数,因此将类型声明为内联而不是作为单独的类型更有意义CustomRefHook

我已允许此挂钩接受any的值,但如果您只想将其应用于 HTML 元素,则T可以使用。T extends HTMLElement这可能很重要,具体取决于您的useEffect. 如果“do stuff”需要任何特定的内容T,那么您需要确保T使用所需的属性/方法扩展某些内容。

import React, { MutableRefObject, DependencyList, useEffect, useRef } from "react";

const useCustomRefHook = <T extends any>( dependencies: DependencyList = [] ): MutableRefObject<T | null> => {

  const ref = useRef<T | null>(null);

  useEffect(() => {
    // ... do stuff
  }, dependencies);

  return ref;
};
Run Code Online (Sandbox Code Playgroud)

该钩子返回一个MutableRefObject<T | null>基于通用的T. 的值T不可能从参数中推断出来,因此每次调用它时都需要指定泛型。

const Test = () => {
  const ref = useCustomRefHook<HTMLButtonElement>();

  return <button ref={ref} />;
};
Run Code Online (Sandbox Code Playgroud)