score:46

Accepted answer

there are two kinds of refs in modern react: ref objects, and ref callbacks. ref objects are what's created by useref (or in class components, createref): it's an object with a current property. in typescript, these have the type refobject<t>, where t is whatever value(s) will be on current.

ref callbacks are another option, which are needed for some advanced cases. you pass a function into the element, and the function will be called back when the instance is created or destroyed. these have the type (instance: t) => void.

a shorthand which combines both the ref object and the ref callback into a single type is ref<t>, and it looks like that's what your code expects. since you haven't shown that code, i'll have to make some educated guesses about it looks like. suppose you have a component which accepts a ref as a prop (perhaps so it can then hand it off to one of its internal components):

interface exampleprops {
  buttonref: ref<htmlbuttonelement>
}

const example: fc<exampleprops> = ({ buttonref }) => {
  return (
    <div>
      <button ref={buttonref}>hello</button>
    <div>
  )
}

since i've defined the prop to be a ref, it can be passed in either a ref object, or a ref callback. that's fine in this case, since i'm not doing anything with it except passing it on to the button. but if i try to write some code to interact with it, i can't assume it to be an object or a function.

if i need to do this, perhaps i could restrict the prop so it only takes ref objects, and then i can assume it will have .current

interface exampleprops {
  buttonref: refobject<htmlbuttonelement>
}

const example: fc<exampleprops> = ({ buttonref }) => {
  useeffect(() => {
    console.log(buttonref.current);
  });
  return (
    <div>
      <button ref={buttonref}>hello</button>
    <div>
  )
}

but maybe i don't want to restrict the way my component can be used, but i still need to be able to interact with the ref somehow. in that case, i'll probably need to make a callback ref of my own, and then add logic to it to handle both my use of the ref, and the prop's use of the 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>
  )
}

the type assertion of as mutablerefobject<htmlbuttonelement> is needed because myref is marked as being immutable. this type reflects the fact that only react is supposed to modify the .current property. that's good for normal use cases, but since we're taking over that responsibility from react, it's ok to change the value.


Related Query

More Query from same tag