typescript 类型“((示例:HTML分类元素|null)=>void)|RefObject< HTMLDivElement>'

dluptydi  于 2023-03-24  发布在  TypeScript
关注(0)|答案(2)|浏览(129)

通常,当我使用React + Typescript时,我必须使用refs,我通常使用这个检查:

const ref = useRef<HTMLDivElement>(null)
...
if(ref && ref.current)

但最近,我收到了这个错误:

Property 'current' does not exist on type '((instance: HTMLDivElement | null) => void) | RefObject<HTMLDivElement>'.
  Property 'current' does not exist on type '(instance: HTMLDivElement | null) => void'.ts(2339)

对于这个错误有什么想法吗?为了解决这个问题,作为一种变通方法,我添加了第三个检查:

if(ref && "current" in ref && ref.current)

但这看起来相当糟糕,主要是当你必须同时与多名裁判合作时。
谢谢你的帮助。

wgeznvg7

wgeznvg71#

在modern react中有两种refs:ref对象和ref回调。Ref对象是由useRef(或在类组件中,createRef)创建的:它是一个具有current属性的对象。在typescript中,这些对象的类型为RefObject<T>,其中Tcurrent上的任何值。
引用回调是另一种选择,在某些高级情况下需要。您将函数传递到元素中,当创建或销毁示例时,该函数将被回调。这些回调的类型为(instance: T) => void
一个将ref对象和ref回调组合成一个类型的简写是Ref<T>,看起来这就是你的代码所期望的。因为你还没有展示这段代码,我不得不做一些有根据的猜测。假设你有一个组件,它接受一个ref作为一个prop(也许这样它就可以把它交给它的一个内部组件):

interface ExampleProps {
  buttonRef: Ref<HTMLButtonElement>
}

const Example: FC<ExampleProps> = ({ buttonRef }) => {
  return (
    <div>
      <button ref={buttonRef}>Hello</button>
    <div>
  )
}

由于我已经将prop定义为一个Ref,所以它可以通过一个ref对象或一个ref回调传递。在这种情况下,这是很好的,因为除了将它传递给按钮之外,我没有对它做任何事情。但是如果我试图编写一些代码来与它交互,我不能假设它是一个对象或函数。
如果我需要这样做,也许我可以限制prop,使它只接受ref对象,然后我可以假设它将有.current

interface ExampleProps {
  buttonRef: RefObject<HTMLButtonElement>
}

const Example: FC<ExampleProps> = ({ buttonRef }) => {
  useEffect(() => {
    console.log(buttonRef.current);
  });
  return (
    <div>
      <button ref={buttonRef}>Hello</button>
    <div>
  )
}

但也许我不想限制组件的使用方式,但我仍然需要能够以某种方式与ref交互,在这种情况下,我可能需要创建自己的回调ref,然后向其添加逻辑来处理我对ref的使用和prop对ref的使用:

interface ExampleProps {
  buttonRef: Ref<HTMLButtonElement>
}

const Example: FC<ExampleProps> = ({ buttonRef }) => {
  const myRef = useRef<HTMLButtonElement>(null);
  useEffect(() => {
    console.log(myRef.current);
  });
  return (
    <div>
      <button ref={(element) => {
        (myRef as MutableRefObject<HTMLButtonElement>).current = element;
        if (typeof buttonRef === 'function') {
          buttonRef(element);
        } else {
          buttonRef.current = element;
        }
      }}>Hello</button>
    <div>
  )
}

as MutableRefObject<HTMLButtonElement>的类型Assert是必需的,因为myRef被标记为不可变的。这个类型反映了只有react才应该修改.current属性的事实。这对于正常的用例来说是很好的,但是因为我们从react那里接管了这个职责,所以可以更改值。

knsnq2tg

knsnq2tg2#

根据Nicholas Tower的回答,我做了一个可重用的类型化util函数来设置可能对其他人有用的两个引用:

import { ForwardedRef, MutableRefObject } from 'react';

export const setComponentRefs =
 <T>(ref: MutableRefObject<T | null>, forwardedRef: ForwardedRef<T>) =>
 (el: T) => {
   ref.current = el;
   if (typeof forwardedRef === 'function') forwardedRef(el);
   else if (forwardedRef) forwardedRef.current = el;
};

///////// Example

<View ref={setComponentRefs(innerRef, ref)}>
 {...}
</View>

相关问题