Search code examples
reactjstypescriptcanvas

How to solve Type 'HTMLCanvasElement' has no call signatures.ts(2349) for React?


I have TS errors in the code I am using for the react-canvas-confetti package. I keep on getting the following error when I am trying to define types for my function which you will see below.

(property) React.MutableRefObject<HTMLCanvasElement | null>.current: HTMLCanvasElement This expression is not callable. Type 'HTMLCanvasElement' has no call signatures.ts(2349)

const refAnimationInstance = useRef<HTMLCanvasElement | null>(null)
  
  const getInstance = useCallback((instance: any) => {
    refAnimationInstance.current = instance
  }, [])

  const makeShot = useCallback((particleRatio: number, opts: any) => {
    refAnimationInstance.current &&
      refAnimationInstance.current({
        ...opts,
        particleCount: Math.floor(200 * particleRatio),
      })
  }, [])

I cannot figure out how to define this so that refAnimationInstance does not throw an error here for .current:

refAnimationInstance.current({
        ...opts,
        particleCount: Math.floor(200 * particleRatio),
      })

You can see the working example of the confetti in this link here: https://codesandbox.io/s/realistic-fn-react-canvas-confetti-forked-sixvv1?file=/src/App.js:904-975


Solution

  • It's pretty annoying that this library doesn't export their types, but you can still get it with this long convoluted usage of built-in types:

    import { type IProps } from "react-canvas-confetti";
    
    type CreateConfetti = NonNullable<Parameters<NonNullable<IProps["refConfetti"]>>[0]>;
    

    Then use the type where you need it:

    const refAnimationInstance = useRef<CreateConfetti | null>(null)
      
    const getInstance = useCallback((instance: CreateConfetti) => {
        refAnimationInstance.current = instance
    }, []);
    

    Also, you can use optional chaining to avoid having to use && short-circuiting:

    refAnimationInstance.current?.({
        ...opts,
        particleCount: Math.floor(200 * particleRatio),
    })