Search code examples
reactjstypescriptcanvasgatsbystyled-components

How to properly use TypeScript types with a Styled Component canvas on React


I am creating a React component on Gatsby using TypeScript and have defined a canvas Styled Component this way:

const Background = styled.canvas`
  position: fixed;
  width: 100%;
  height: 100%;
`;

And to use it I am assigning types to it this way:

const canvas: HTMLCanvasElement = Background,
  context = Background.getContext('2d');

But I am getting this error with the canvas type:

enter image description here

Type 'String & StyledComponentBase<"canvas", any, {}, never> & NonReactStatics<never, {}>' is missing the following properties from type 'HTMLCanvasElement': height, width, getContext, toBlob, and 238 more.

I am also getting an error on the .getContext() method:

enter image description here

This expression is not callable.
Type 'never' has no call signatures.

I have been searching for a solution but can not find a proper one for this specific problem. Could someone please explain to me the best way to use Styled Component canvas with TypeScript?


Solution

  • The answer from @101arrowz was almost right but had a problem with the context that gave me this error.

    enter image description here

    Object is possibly 'null'.
    

    But it helped me to find a different approach with the styles being inline and solve the problem this way:

    const Component: React.FC = () => {
      const canvasRef = React.useRef<HTMLCanvasElement>(null);
      const [context, setContext] = React.useState<CanvasRenderingContext2D | null>(
        null
      );
    
      React.useEffect(() => {
        if (canvasRef.current) {
          const renderCtx = canvasRef.current.getContext('2d');
    
          if (renderCtx) {
            setContext(renderCtx);
          }
        }
      }, [context]);
    
      return (
        <div>
          <canvas
            id="canvas"
            ref={canvasRef}
            style={{
              position: 'fixed',
              width: '100%',
              height: '100%'
            }}
          ></canvas>
        </div>
      );