title: Property 'current' does not exist on type '[boolean, Dispatch<SetStateAction<boolean>>]'.ts(2339)
body: <p>I am adding cursor animations to a React/Typescript project and in researching came across a CodePen (<a href="https://codepen.io/StephenScaff/pen/Jjdveyw" rel="nofollow noreferrer">Animated Cursor
  React Component</a>) that works perfectly well.</p>
  
  <p>However, when converting to a Typescript file I come across the error <code>Property 'current' does not exist on type '[boolean, Dispatch&lt;SetStateAction&lt;boolean&gt;&gt;]'.ts(2339)</code> on <code>cursorVisible.current</code> in</p>
  
  <pre><code>const onMouseEnter = () =&gt; {
    cursorVisible.current = true;
    toggleCursorVisibility();
  };
  </code></pre>
  
  <p>Property <code>cursorVisible</code> is from <code>const cursorVisible = useState(false);</code></p>
  
  <p>What does Typescript need me to do so <code>current</code> works in Typescript? Reading the React Hooks docs, I could not see reference to <code>current</code> on <code>useState</code> and interestingly this works as a <code>js</code> file, only not in <code>ts</code>.</p>
  
  <p>In the past I have used <code>current</code> with <code>ref</code> but never across <code>useState</code> hook. </p>
  
  <p>Full file is</p>
  
  <pre><code>import React, { useEffect, useRef, useState } from 'react';
  
  import MobileDetect from './MobileDetect';
  
  interface CursorProps {
      color: string;
      outlineAlpha: number;
      dotSize: number;
      outlineSize: number;
      outlineScale: number;
      dotScale: number;
  }
  
  function AnimatedCursor({
      color = '220, 90, 90',
      outlineAlpha = 0.3,
      dotSize = 8,
      outlineSize = 8,
      outlineScale = 5,
      dotScale = 0.7,
  }: CursorProps) {
      // Bail if Mobile
      if (typeof navigator !== 'undefined' &amp;&amp; MobileDetect!.anyMobile())
          return &lt;&gt;&lt;/&gt;;
  
      const cursorOutline = useRef();
      const cursorDot = useRef();
      const requestRef = useRef();
      const previousTimeRef = useRef();
      const [width, setWidth] = useState(window.innerWidth);
      const [height, setHeight] = useState(window.innerHeight);
      const [mousePosition, setMousePosition] = useState({ x: 0, y: 0 });
      const cursorVisible = useState(false);
      const cursorEnlarged = useState(false);
  
      const styles = {
          cursors: {
              zIndex: 999,
              pointerEvents: 'none',
              position: 'absolute',
              top: '50%',
              left: '50%',
              borderRadius: '50%',
              opacity: 0,
              transform: 'translate(-50%, -50%)',
              transition: 'opacity 0.15s ease-in-out, transform 0.15s ease-in-out',
          },
          cursorDot: {
              width: dotSize,
              height: dotSize,
              backgroundColor: `rgba(${color}, 1)`,
          },
          cursorOutline: {
              width: outlineSize,
              height: outlineSize,
              backgroundColor: `rgba(${color}, ${outlineAlpha})`,
          },
      };
  
      // Hide default cursor
      document.body.style.cursor = 'none';
  
      // Mouse Events
      const onMouseMove = (event: { pageX: number; pageY: number }) =&gt; {
          const { pageX: x, pageY: y } = event;
          setMousePosition({ x, y });
          positionDot(event);
      };
      const onMouseEnter = () =&gt; {
          cursorVisible.current = true;
          toggleCursorVisibility();
      };
      const onMouseLeave = () =&gt; {
          cursorVisible.current = false;
          toggleCursorVisibility();
      };
      const onMouseDown = () =&gt; {
          cursorEnlarged.current = true;
          toggleCursorSize();
      };
      const onMouseUp = () =&gt; {
          cursorEnlarged.current = false;
          toggleCursorSize();
      };
  
      // Set window hxw
      const onResize = () =&gt; {
          setWidth(window.innerWidth);
          setHeight(window.innerHeight);
      };
  
      /**
       * Hooks
       */
      useEffect(() =&gt; {
          // Bail if mobile
          document.addEventListener('mousemove', onMouseMove);
          document.addEventListener('mouseenter', onMouseEnter);
          document.addEventListener('mouseleave', onMouseLeave);
          document.addEventListener('mousedown', onMouseDown);
          document.addEventListener('mouseup', onMouseUp);
          window.addEventListener('resize', onResize);
          requestRef.current = requestAnimationFrame(animateDotOutline);
          handleLinkEvents();
  
          return () =&gt; {
              document.removeEventListener('mousemove', onMouseMove);
              document.removeEventListener('mouseenter', onMouseEnter);
              document.removeEventListener('mouseleave', onMouseLeave);
              document.removeEventListener('mousedown', onMouseDown);
              document.removeEventListener('mouseup', onMouseUp);
              window.removeEventListener('resize', onResize);
              cancelAnimationFrame(requestRef.current);
          };
          // eslint-disable-next-line react-hooks/exhaustive-deps
      }, []);
  
      let { x, y } = mousePosition;
      const winDimensions = { width, height };
      let endX = winDimensions.width / 2;
      let endY = winDimensions.height / 2;
  
      /**
       * Toggle Cursor Visiblity
       */
      function toggleCursorVisibility() {
          if (cursorVisible.current) {
              cursorDot.current.style.opacity = 1;
              cursorOutline.current.style.opacity = 1;
          } else {
              cursorDot.current.style.opacity = 0;
              cursorOutline.current.style.opacity = 0;
          }
      }
  
      /**
       * Position Dot (cursor)
       * @param {event}
       */
      function positionDot(e: { pageX: number; pageY: number }) {
          cursorVisible.current = true;
          toggleCursorVisibility();
          // Position the dot
          endX = e.pageX;
          endY = e.pageY;
          cursorDot.current.style.top = `${endY}px`;
          cursorDot.current.style.left = `${endX}px`;
      }
  
      /**
       * Toggle Cursors Size/Scale
       */
      function toggleCursorSize() {
          if (cursorEnlarged.current) {
              cursorDot.current.style.transform = `translate(-50%, -50%) scale(${dotScale})`;
              cursorOutline.current.style.transform = `translate(-50%, -50%) scale(${outlineScale})`;
          } else {
              cursorDot.current.style.transform = 'translate(-50%, -50%) scale(1)';
              cursorOutline.current.style.transform = 'translate(-50%, -50%) scale(1)';
          }
      }
  
      /**
       * Handle Links Events
       * Applies mouseover/out hooks on all links
       * to trigger cursor animation
       */
      function handleLinkEvents() {
          document.querySelectorAll('a').forEach((el) =&gt; {
              el.addEventListener('mouseover', () =&gt; {
                  cursorEnlarged.current = true;
                  toggleCursorSize();
              });
              el.addEventListener('mouseout', () =&gt; {
                  cursorEnlarged.current = false;
                  toggleCursorSize();
              });
          });
      }
  
      /**
       * Animate Dot Outline
       * Aniamtes cursor outline with trailing effect.
       * @param {number} time
       */
      const animateDotOutline = (time: undefined) =&gt; {
          if (previousTimeRef.current !== undefined) {
              x += (endX - x) / 8;
              y += (endY - y) / 8;
              cursorOutline.current.style.top = `${y}px`;
              cursorOutline.current.style.left = `${x}px`;
          }
          previousTimeRef.current = time;
          requestRef.current = requestAnimationFrame(animateDotOutline);
      };
  
      return (
          &lt;&gt;
              &lt;div
                  ref={cursorOutline}
                  id="cursor-outline"
                  style={{ ...styles.cursors, ...styles.cursorOutline }}
              /&gt;
              &lt;div
                  ref={cursorDot}
                  id="cursor-inner"
                  style={{ ...styles.cursors, ...styles.cursorDot }}
              /&gt;
          &lt;/&gt;
      );
  }
  
  export default AnimatedCursor;
  </code></pre>