React Bootstrap ListGroup的实现类型问题



我正在这个React应用程序中实现typescript。我正在使用react引导程序(已安装类型(。我有一个行动项目列表组,如下所示。要获取我拥有的每个项目的点击事件的类型:((event: React.MouseEvent<HTMLAnchorElement, MouseEvent>) => void)不确定为什么它建议使用这种类型,因为当我检查DOM时,我会看到按钮。以下是列表组的代码。

<ListGroup id="riskQuestion-1" >
<ListGroup.Item action onClick={(event:((event: React.MouseEvent<HTMLAnchorElement, MouseEvent>) => void) | undefined) => handleInput(setRiskAnswer1, 5, event)} >I was great!</ListGroup.Item>
<ListGroup.Item action onClick={(event:((event: React.MouseEvent<HTMLAnchorElement, MouseEvent>) => void) | undefined) => handleInput(setRiskAnswer2, 3, event)}>I did good but can be better</ListGroup.Item>
</ListGroup>

那么我的handleInput函数是:

const [riskAnswer1, setRiskAnswer1] = useState<number | null>(null);
const [riskAnswer2, setRiskAnswer2] = useState<number | null>(null);
interface InputParams {
answerHandler:React.Dispatch<React.SetStateAction<number | null>>,
value: number,
event: ((event: React.MouseEvent<HTMLAnchorElement, MouseEvent>) => void) | undefined
}
function handleInput({answerHandler, value, event}:InputParams) {
event.preventDefault();
const parentEl = event.target.parentNode;
const  parentId = parentEl.getAttribute("id");
if (parentId) {
const el = document.getElementById(parentId);
if (el) {
for (let i=0; i < el.children.length; i++) {
if (el.children[i].classList.contains('selected')) {
el.children[i].classList.remove('selected');
}
}
}
}

event.target.classList.add("selected");
answerHandler(value);
}

我在这段代码中确实有一些event.target问题,但这可能与手头的主要问题有关,也可能与之无关。现在的主要问题是typescript在onClick上仍然显示错误。当我悬停在它上面时,下面就是我所看到的。

(JSX attribute) onClick?: ((event: React.MouseEvent<HTMLAnchorElement, MouseEvent>) => void) | undefined
No overload matches this call.
Overload 1 of 2, '(props: ReplaceProps<"a", BsPrefixProps<"a"> & ListGroupItemProps> | Readonly<ReplaceProps<"a", BsPrefixProps<"a"> & ListGroupItemProps>>): ListGroupItem<...>', gave the following error.
Type '(event: ((event: React.MouseEvent<HTMLAnchorElement, MouseEvent>) => void) | undefined) => void' is not assignable to type '(event: MouseEvent<HTMLAnchorElement, MouseEvent>) => void'.
Types of parameters 'event' and 'event' are incompatible.
Type 'MouseEvent<HTMLAnchorElement, MouseEvent>' is not assignable to type '(event: MouseEvent<HTMLAnchorElement, MouseEvent>) => void'.
Type 'MouseEvent<HTMLAnchorElement, MouseEvent>' provides no match for the signature '(event: MouseEvent<HTMLAnchorElement, MouseEvent>): void'.
Overload 2 of 2, '(props: ReplaceProps<"a", BsPrefixProps<"a"> & ListGroupItemProps>, context: any): ListGroupItem<"a">', gave the following error.
Type '(event: ((event: React.MouseEvent<HTMLAnchorElement, MouseEvent>) => void) | undefined) => void' is not assignable to type '(event: MouseEvent<HTMLAnchorElement, MouseEvent>) => void'.ts(2769)
index.d.ts(1455, 9): The expected type comes from property 'onClick' which is declared here on type 'IntrinsicAttributes & IntrinsicClassAttributes<ListGroupItem<"a">> & Readonly<ReplaceProps<"a", BsPrefixProps<"a"> & ListGroupItemProps>> & Readonly<...>'
index.d.ts(1455, 9): The expected type comes from property 'onClick' which is declared here on type 'IntrinsicAttributes & IntrinsicClassAttributes<ListGroupItem<"a">> & Readonly<ReplaceProps<"a", BsPrefixProps<"a"> & ListGroupItemProps>> & Readonly<...>'
Peek Problem (Alt+F8)
No quick fixes available

所以有两个问题:

1-我需要什么来更改

2-一开始,我把参数的所有类型都放在括号内,但我把它们移到了interface InputParams。现在我在listgroup项上调用handleInput,我看到了这个错误:Expected 1 arguments, but got 3.ts(2554)所以function handleInput({answerHandler, value, event}:InputParams) {似乎不是实现这里的类型的正确方法?不要担心,上面的所有错误都是在我内联所有参数类型时生成的。所以这只是我想问的额外问题。

感谢您的指导。非常感谢。

问题是onClick处理程序的当前类型签名基本上声明参数event本身就是一个函数。为了纠正这一点,您只需要使用事件本身的类型:

<ListGroup id="riskQuestion-1">
<ListGroup.Item
action
onClick={(event: React.MouseEvent<HTMLAnchorElement, MouseEvent>) =>
handleInput(setRiskAnswer1, 5, event)
}
>
I was great!
</ListGroup.Item>
<ListGroup.Item
action
onClick={(event: React.MouseEvent<HTMLAnchorElement, MouseEvent>) =>
handleInput(setRiskAnswer2, 3, event)
}
>
I did good but can be better
</ListGroup.Item>
</ListGroup>

事实上,由于您不想访问仅在<a>元素上找到的属性,因此可以将类型默认为最广泛的类型:Element,因此可以省略泛型。这里之所以是HTMLAnchorElement,是因为带有actionListGroup.Item会呈现一个链接——使用浏览器的开发工具的DOM检查器查看生成的HTML。你会在那里看到一个<a>。尽管它可以是任何东西,而且实际上您可以通过as道具指定它。

<ListGroup id="riskQuestion-1">
<ListGroup.Item
action
onClick={(event: React.MouseEvent) =>
handleInput(setRiskAnswer1, 5, event)
}
>
I was great!
</ListGroup.Item>
<ListGroup.Item
action
onClick={(event: React.MouseEvent) =>
handleInput(setRiskAnswer2, 3, event)
}
>
I did good but can be better
</ListGroup.Item>
</ListGroup>

为了解决您的第二个问题,function handleInput({answerHandler, value, event}:InputParams)是一个接受一个参数的函数,该参数是一个具有这些属性的对象。然而,您使用三个单独的参数调用handleInput,因此它应该是:

function handleInput(
answerHandler: React.Dispatch<React.SetStateAction<number | null>>,
value: number,
event: React.MouseEvent
)

由于你没有在这里使用功能更新,你可以通过以下方式逃脱惩罚:

function handleInput(
answerHandler: (answer: number | null) => void,
value: number,
event: React.MouseEvent
)

在修复了这些问题之后,handleInput中还会出现一些问题。第一个是event.target可能不是元素,因此其类型不具有.parentNode。在这种情况下,最好使用.currentTarget。另请参阅javascript中currentTarget属性和target属性之间的确切区别。

修改后,功能将为:

function handleInput(
answerHandler: (answer: number | null) => void,
value: number,
event: React.MouseEvent
) {
event.preventDefault();
const parentEl = event.currentTarget.parentNode;
const parentId = parentEl.getAttribute("id");
if (parentId) {
const el = document.getElementById(parentId);
if (el) {
for (let i = 0; i < el.children.length; i++) {
if (el.children[i].classList.contains("selected")) {
el.children[i].classList.remove("selected");
}
}
}
}
event.currentTarget.classList.add("selected");
answerHandler(value);
}

但遗憾的是,又出现了一个错误。这一次是因为parentNode属于Node类型。实际上有许多节点类型;元素";只是其中之一!但很明显,您实际上对父元素感兴趣,因此通过将parentNode更改为parentElement,该函数将编译:

function handleInput(
answerHandler: (answer: number | null) => void,
value: number,
event: React.MouseEvent
) {
event.preventDefault();
const parentEl = event.currentTarget.parentElement;
const parentId = parentEl.getAttribute("id");
if (parentId) {
const el = document.getElementById(parentId);
if (el) {
for (let i = 0; i < el.children.length; i++) {
if (el.children[i].classList.contains("selected")) {
el.children[i].classList.remove("selected");
}
}
}
}
event.currentTarget.classList.add("selected");
answerHandler(value);
}

最后,我要说的是,这种直接的DOM操作在React世界中相当粗略,在大多数情况下可以而且应该使用React来实现。

最新更新