title: Typescript: how to declare a type that includes all types extending a common type?
body: <p><strong>TLDR:</strong> Is there a way in Typescript to declare a type that encompasses all types that extend a given interface?</p>
  
  <p><strong>My specific problem</strong></p>
  
  <p>I am writing a custom React hook that encapsulates logic for deciding whether or not an element is moused over. It is modelled roughly after <a href="https://github.com/Lizhooh/react-hooks-use-hover" rel="noreferrer">this hook</a>. It exposes a ref that should be able to take any HTMLElement:</p>
  
  <p><code>const ref = useRef&lt;HTMLElement&gt;(null);</code></p>
  
  <p>The problem is, if I try to use this ref on any specific React element, I get an error telling me that this specific element is not quite <code>HTMLElement</code>. For example, if I use it with <code>HTMLDivElement</code>, I get this error: <code>argument of type HTMLElement is not assignable to parameter of type HTMLDivElement</code>.</p>
  
  <p>Here's <a href="https://www.typescriptlang.org/play/#code/MYewdgzgLgBAHgLhgCQCoFkAyBRANgUwFt8xYBeGMfAdxQxwONIAoBKAbgChRJYBPJGiwARAJYA3PERLlKNOiIlSmUNl04AzAK5hgUUeBhR80ZvlyD6YyYxmsYAb04wXMHhBAEAdLhABzZgByAAt8ACd8GFEIGHNpUkCAGljcDk4AX05OY1M4DiA" rel="noreferrer">a simple repro case of the problem above in Typescript playground</a></p>
  
  <p>Obviously, I wouldn't want to list types of all html elements in my hook. Given that <code>HTMLDivElement</code> extends the <code>HTMLElement</code> type, is there a way of declaring that the type that I am actually after is not strictly <code>HTMLElement</code>, but whatever extends <code>HTMLElement</code>?</p>
  
  <hr>
  
  <p><strong>React code example</strong></p>
  
  <p>source code of the hook</p>
  
  <pre><code>import { useRef, useState, useEffect } from 'react';
  
  type UseHoverType = [React.RefObject&lt;HTMLElement&gt;, boolean];
  
  export default function useHover(): UseHoverType {
    const [isHovering, setIsHovering] = useState(false);
    let isTouched = false;
  
    const ref = useRef&lt;HTMLElement&gt;(null); // &lt;-- What should the type be here?
  
    const handleMouseEnter = () =&gt; {
      if (!isTouched) {
        setIsHovering(true);
      }
      isTouched = false;
    };
    const handleMouseLeave = () =&gt; {
      setIsHovering(false);
    };
  
    const handleTouch = () =&gt; {
      isTouched = true;
    };
  
    useEffect(() =&gt; {
      const element = ref.current;
      if (element) {
        element.addEventListener('mouseenter', handleMouseEnter);
        element.addEventListener('mouseleave', handleMouseLeave);
        element.addEventListener('touchstart', handleTouch);
  
        return () =&gt; {
          element.removeEventListener('mouseenter', handleMouseEnter);
          element.removeEventListener('mouseleave', handleMouseLeave);
          element.removeEventListener('touchend', handleTouch);
        };
      }
    }, [ref.current]);
  
    return [ref, isHovering];
  }
  </code></pre>
  
  <p>which produces type error if used like this:</p>
  
  <pre><code>import useHover from 'path-to-useHover';
  
  const testFunction = () =&gt; {
    const [hoverRef, isHovered] = useHover();
  
    return (
       &lt;div
        ref={hoverRef}
       &gt;
        Stuff
       &lt;/div&gt;
    );
  
  }
  </code></pre>
  
  <p>Type error in example above will be:</p>
  
  <pre><code>Type 'RefObject&lt;HTMLElement&gt;' is not assignable to type 'string | RefObject&lt;HTMLDivElement&gt; | ((instance: HTMLDivElement | null) =&gt; void) | null | undefined'.
    Type 'RefObject&lt;HTMLElement&gt;' is not assignable to type 'RefObject&lt;HTMLDivElement&gt;'.
      Property 'align' is missing in type 'HTMLElement' but required in type 'HTMLDivElement'.
  </code></pre>