gpt4 book ai didi

reactjs - Typescript:如何声明一个包含扩展公共(public)类型的所有类型的类型?

转载 作者:行者123 更新时间:2023-12-03 14:17:18 27 4
gpt4 key购买 nike

TLDR:在 Typescript 中是否有一种方法可以声明包含扩展给定接口(interface)的所有类型的类型?

我的具体问题

我正在编写一个自定义 React 钩子(Hook),它封装了用于决定鼠标是否悬停在元素上的逻辑。它大致模仿 this hook 。它公开了一个应该能够接受任何 HTMLElement 的 ref:

const ref = useRef<HTMLElement>(null);

问题是,如果我尝试在任何特定的 React 元素上使用此引用,我会收到一条错误消息,告诉我该特定元素不完全 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

显然,我不想列出我的钩子(Hook)中所有 html 元素的类型。鉴于HTMLDivElement扩展 HTMLElement类型,有没有一种方法可以声明我实际上所追求的类型并不严格 HTMLElement ,但无论扩展HTMLElement

<小时/>

react 代码示例

钩子(Hook)的源代码

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'.

最佳答案

我认为您对失败作业的方向有误。如果您有一个接口(interface) A,那么与 A 的所有子类匹配的类型就称为 A。这样,HTMLElement(即可分配from)任何 HTML 元素,例如HTMLDivElement

这意味着,如果您有一堆函数,其中一个接受 HTMLDivElement,另一个接受 HTMLLinkElement 等,那么就没有可以传递给的实际类型他们全部。这意味着您希望有一个既是 div 又是链接等的元素。

根据您对问题的编辑进行编辑:如果您的代码工作正常,并且唯一的问题是它无法编译,那么只需使您的 useHover 通用,如下所示:

type UseHoverType<T extends HTMLElement> = [React.RefObject<T>, boolean];

function useHover<T extends HTMLElement>(): UseHoverType<T> {
const ref = useRef<T>(null); // <-- What should the type be here?
...

然后:

const testFunction = () => {
const [hoverRef, isHovered] = useHover<HTMLDivElement>();

这样的事情将使您的代码编译良好,而不改变其运行时行为。我无法判断现在的运行时行为是否符合预期。

关于reactjs - Typescript:如何声明一个包含扩展公共(public)类型的所有类型的类型?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57201223/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com