onClick and handleClick functions on a Styled Component with TypeScript

Viewed 74

This is a problem I am trying to solve for days. I am using React with TypeScript and Styled Components.

I am trying to port a minesweeper game I originally made in p5js. I am trying to figure out how to add event listeners to the cells. It have been a huge mess, thus before sharing my code (if needed), I would like to ask how this can be done.

I have any array of cell objects in my state (cells). Each cell is a StyledCell component. No matter what I've tried I couldn't attach an onClick property. I have seen every possible error.

Can someone please show me how it can be done?

I am here for any additional information you need.

Edit: After simplifying my code in order to make it easier to follow I will share one of the problematic parts:

import React from "react";
import styled from "styled-components";
import { WON, LOST, EMPTY, MINE, DETONATION, FLAG, DIGITS } from "../../emojis";

interface CellProps extends React.HTMLAttributes<HTMLElement> {
  num: number;
  i: number;
  j: number;
  mine: boolean;
  minesAround: number;
  revealed: boolean;
  clicked: boolean;
  flagged: boolean;
  won: boolean;
  lost: boolean;
  size: string;
  // revealCell: (num: number) => Array<CellType>;
  // onClick: React.MouseEventHandler<HTMLButtonElement>;
  revealCell: (e: React.MouseEvent<HTMLButtonElement>) => void;
  // revealCell: (num: number) => void;

}

const StyledCell = styled.div<CellProps>`
  width: 38px;
  height: 38px;
  line-height: 38px;
  font-size: 38px;
  margin: 1px;
  padding: 0;
  text-align: center;
  display: flex;
  justify-content: center;
  align-items: center;
`;

export const Cell: React.FC<CellProps> = ({
  num,
  mine,
  minesAround,
  revealed,
  clicked,
  flagged,
  won,
  lost,
  size,
  revealCell,
}) => {
  function render() {
    if (revealed && clicked && mine) {
      return DETONATION;
      //
    }
    if (revealed && mine) {
      return MINE;
    }
    if (revealed) {
      // If won, empty cells show the happy face
      if (won && minesAround === 0) {
        return WON;
        // If lost, empty cells show the sad face
      } else if (lost && minesAround === 0) {
        return LOST;
      }
      // Calculate the number of mines around and draw that
      return DIGITS[minesAround];
    }
    if (flagged) {
      return FLAG;
    }

    return EMPTY;
  }

  return <StyledCell onClick={revealCell}>{render()}</StyledCell>;
};

In the line:

 return <StyledCell onClick={revealCell}>{render()}</StyledCell>;

onClick is marked as an error and the error message I get is this:

(property) onClick?: (React.MouseEventHandler & React.MouseEventHandler) | undefined No overload matches this call. Overload 1 of 2, '(props: { i: number; slot?: string | undefined; style?: CSSProperties | undefined; title?: string | undefined; ref?: ((instance: HTMLDivElement | null) => void) | RefObject<...> | null | undefined; ... 262 more ...; revealCell: (e: MouseEvent<...>) => void; } & { ...; } & { ...; }): ReactElement<...>', gave the following error. Type '(e: MouseEvent<HTMLButtonElement, MouseEvent>) => void' is not assignable to type 'MouseEventHandler & MouseEventHandler'. Type '(e: MouseEvent<HTMLButtonElement, MouseEvent>) => void' is not assignable to type 'MouseEventHandler'. Types of parameters 'e' and 'event' are incompatible. Type 'MouseEvent<HTMLDivElement, MouseEvent>' is not assignable to type 'MouseEvent<HTMLButtonElement, MouseEvent>'. Type 'HTMLDivElement' is missing the following properties from type 'HTMLButtonElement': disabled, form, formAction, formEnctype, and 13 more. Overload 2 of 2, '(props: StyledComponentPropsWithAs<"div", any, CellProps, never, "div", "div">): ReactElement<StyledComponentPropsWithAs<"div", any, CellProps, never, "div", "div">, string | JSXElementConstructor<...>>', gave the following error. Type '(e: MouseEvent<HTMLButtonElement, MouseEvent>) => void' is not assignable to type 'MouseEventHandler & MouseEventHandler'.ts(2769) index.d.ts(1479, 9): The expected type comes from property 'onClick' which is declared here on type 'IntrinsicAttributes & { i: number; slot?: string | undefined; style?: CSSProperties | undefined; title?: string | undefined; ref?: ((instance: HTMLDivElement | null) => void) | RefObject<...> | null | undefined; ... 262 more ...; revealCell: (e: MouseEvent<...>) => void; } & { ...; } & { ...; }' index.d.ts(1479, 9): The expected type comes from property 'onClick' which is declared here on type 'IntrinsicAttributes & { i: number; slot?: string | undefined; style?: CSSProperties | undefined; title?: string | undefined; ref?: ((instance: HTMLDivElement | null) => void) | RefObject<...> | null | undefined; ... 262 more ...; revealCell: (e: MouseEvent<...>) => void; } & { ...; } & { ...; }'

I have tried any possible solution I could think of.

1 Answers

Does this codesandbox help you ?

https://codesandbox.io/s/magical-butterfly-4jjo0n?file=/src/App.tsx

import "./styles.css";
import styled from "styled-components";

const StyledApp = styled.main`
  display: flex;
  gap: 1rem;
`;

const StyledCell = styled.div`
  height: 100px;
  width: 100px;
  background-color: black;
`;

export default function App() {
  const numberOfCells = 10;
  return (
    <StyledApp>
      {[...Array(numberOfCells)].map((_, index) => (
        <StyledCell
          onClick={() => alert(`you clicked the ${index + 1}nth cell`)}
        />
      ))}
    </StyledApp>
  );
}
Related