reactjstypescript

declare type with React.useImperativeHandle()


function App(){
  const cntEl:any = React.useRef(null);  // I don't know what type should be here.
  React.useEffect(()=>{
    if(cntEl.current){ cuntEl.current.start() }
  }, []);
  return <Countdown ref={cntEl} />
}
const Countdown = React.forwardRef((props,ref) => {
  React.useImperativeHandle(ref, ()=>({
    start() {
      alert('Start');
    }
  });
  return <div>Countdown</div>
});

I try to use a child method in a parent component using ref and React.useImperativeHandle().

It works well.

but I am not satisfied because of const cntEl:any.

I believe there are many ways to avoid using any type I don't know.

I just need a type that could be replaced type any.

Edited

I can see (property) React.MutableRefObject<null>.current: null when I hover at cntEl.current


Solution

  • I recommend you use type definitions more explicitly

    For example, with React DT, you can define ref exotic component with ForwardRefRenderFunction instead of FC.

    type CountdownProps = {}
        
    type CountdownHandle = {
      start: () => void,
    }
        
    const Countdown: React.ForwardRefRenderFunction<CountdownHandle, CountdownProps> = (
      props,
      forwardedRef,
    ) => {
      React.useImperativeHandle(forwardedRef, ()=>({
        start() {
          alert('Start');
        }
      });
    
      return <div>Countdown</div>;
    }
    
    export default React.forwardRef(Countdown);
    

    and then use React utility ElementRef, TypeScript can infer exact ref type of your component

    const App: React.FC = () => {
      // this will be inferred as `CountdownHandle`
      type CountdownHandle = React.ElementRef<typeof Countdown>;
    
      const ref = React.useRef<CountdownHandle>(null); // assign null makes it compatible with elements.
    
      return (
        <Countdown ref={ref} />
      );
    };