agilgur5 / react-signature-canvas

A React wrapper component around signature_pad (in < 150 LoC). Unopinionated and heavily updated fork of react-signature-pad
https://agilgur5.github.io/react-signature-canvas/
Other
546 stars 119 forks source link

Do I need to install @types/react-signature-canvas ? #106

Closed praveenpuglia closed 6 months ago

praveenpuglia commented 6 months ago

Now that it's written in typescript and can export the typings from the tsx files directly, do I still need to install the @types package?

I have checked the published package for react-signature-canvas and that doesn't contain any typings all by itself.

Here's my tsx code where the ref complains of type issues.

const SignatureCanvas = lazy(() => import('react-signature-canvas'));

export const DrawSignature = () => {
    const canvasRef = useRef<typeof SignatureCanvas>(null);

    return (
      <Suspense>
        <SignatureCanvas
          ref={canvasRef}
          canvasProps={{
            className: styles['canvas'],
          }}
          backgroundColor={backgroundBlue}
        />
      </Suspense>
    )
}

Here, the ref on the component complains.

Type 'RefObject<LazyExoticComponent<typeof ReactSignatureCanvas>>' is not assignable to type 'Ref<ReactSignatureCanvas> | undefined'.
  Type 'RefObject<LazyExoticComponent<typeof ReactSignatureCanvas>>' is not assignable to type 'RefObject<ReactSignatureCanvas>'.
    Type 'LazyExoticComponent<typeof ReactSignatureCanvas>' is not assignable to type 'ReactSignatureCanvas'.ts(2322)
index.d.ts(119, 9): The expected type comes from property 'ref' which is declared here on type 'IntrinsicAttributes & ReactSignatureCanvasProps & RefAttributes<ReactSignatureCanvas>'

I have looked at other issues like https://github.com/agilgur5/react-signature-canvas/issues/61 but those examples don't work.

agilgur5 commented 6 months ago

do I still need to install the @types package?

For v1.0.x, yes.

I have checked the published package for react-signature-canvas and that doesn't contain any typings all by itself.

The latest published package is older than most of the TS changes.

I had been meaning to publish a v1.1.0-beta with the built-in TS types, but never quite got to it (I maintain a lot of projects 🙃, this is one of the most stable of them all). Once that is published and you install v1.1.x+, you will no longer need @types/react-signature-canvas.

praveenpuglia commented 6 months ago

For anyone looking to lazy load this component and struggling with the exact type you need for useRef<T>, here's the solution.

When you lazy load a component like this...

const SignatureCanvas = lazy(() => import('react-signature-canvas'));

the type you get for SignatureCanvas is LazyExoticComponent<typeof ReactSignatureCanvas>.

What we really need is the ReactSignatureCanvas type to pass onto useRef<T> as T

We need to extract it out. This is where the following two type utils come into picture.

type UnwrapLazyComponent<T> = T extends React.LazyExoticComponent<
  infer ComponentType
>
  ? ComponentType
  : never;

This first one extracts the typeof ReactSignatureCanvas from LazyExoticComponent<typeof ReactSignatureCanvas>

// eslint-disable-next-line @typescript-eslint/no-explicit-any
type InstanceTypeOf<T extends new (...args: any) => any> = T extends new (
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
  ...args: any
) => infer K
  ? K
  : never;

This second one extracts the ReactSignatureCanvas type from typeof ReactSignatureCanvas. It does so by asking - hey if this instance is of type T what's T ? infer that and return.

You can then get your required type like this and pass it on to useRef

type ReactSignatureCanvasType = InstanceTypeOf<
  UnwrapLazyComponent<typeof ReactSigCanvas>
>;

const canvasRef = useRef<ReactSignatureCanvasType>(null);

Courtesy : Myself and Copilot with a little bit of toying around.