【发布时间】:2019-12-03 16:30:45
【问题描述】:
TLDR:Typescript 中有没有一种方法可以声明一个类型,该类型包含扩展给定接口的所有类型?
我的具体问题
我正在编写一个自定义的 React 钩子,它封装了决定一个元素是否被鼠标悬停的逻辑。它大致仿照this hook。它公开了一个应该能够接受任何 HTMLElement 的 ref:
const ref = useRef<HTMLElement>(null);
问题是,如果我尝试在任何特定的 React 元素上使用这个 ref,我会收到一个错误,告诉我这个特定的元素不完全是 HTMLElement。例如,如果我将它与 HTMLDivElement 一起使用,我会收到以下错误:argument of type HTMLElement is not assignable to parameter of type HTMLDivElement。
这里是a simple repro case of the problem above in Typescript playground
显然,我不想在我的钩子中列出所有 html 元素的类型。鉴于HTMLDivElement 扩展了HTMLElement 类型,有没有办法声明我实际追求的类型不是严格意义上的HTMLElement,而是扩展HTMLElement?
反应代码示例
钩子的源代码
import { useRef, useState, useEffect } from 'react';
type UseHoverType = [React.RefObject<HTMLElement>, boolean];
export default function useHover(): UseHoverType {
const [isHovering, setIsHovering] = useState(false);
let isTouched = false;
const ref = useRef<HTMLElement>(null); // <-- What should the type be here?
const handleMouseEnter = () => {
if (!isTouched) {
setIsHovering(true);
}
isTouched = false;
};
const handleMouseLeave = () => {
setIsHovering(false);
};
const handleTouch = () => {
isTouched = true;
};
useEffect(() => {
const element = ref.current;
if (element) {
element.addEventListener('mouseenter', handleMouseEnter);
element.addEventListener('mouseleave', handleMouseLeave);
element.addEventListener('touchstart', handleTouch);
return () => {
element.removeEventListener('mouseenter', handleMouseEnter);
element.removeEventListener('mouseleave', handleMouseLeave);
element.removeEventListener('touchend', handleTouch);
};
}
}, [ref.current]);
return [ref, isHovering];
}
这样使用会产生类型错误:
import useHover from 'path-to-useHover';
const testFunction = () => {
const [hoverRef, isHovered] = useHover();
return (
<div
ref={hoverRef}
>
Stuff
</div>
);
}
上面示例中的类型错误将是:
Type 'RefObject<HTMLElement>' is not assignable to type 'string | RefObject<HTMLDivElement> | ((instance: HTMLDivElement | null) => void) | null | undefined'.
Type 'RefObject<HTMLElement>' is not assignable to type 'RefObject<HTMLDivElement>'.
Property 'align' is missing in type 'HTMLElement' but required in type 'HTMLDivElement'.
【问题讨论】:
-
“在任何特定的 React 元素上使用这个 ref”到底是什么意思?哪些代码不能为你编译?
-
@TPReal 我添加了一个中断的代码示例。
标签: reactjs typescript