javascript - React + TypeScript:滚动事件类型不可分配给 window.addEventListener
问题描述
事件的 TypeScript DOM 类型和 React 事件类型不能与其他类型配合得很好吗?
看看这段代码:
useEffect(() => {
const onScroll = (event: React.ChangeEvent<Body>) => {
console.log("event", event.target);
};
window.addEventListener("scroll", onScroll);
return () => window.removeEventListener("scroll", onScroll);
}, []);
它抛出
No overload matches this call.
Overload 1 of 2, '(type: "scroll", listener: (this: Window, ev: Event) => any, options?: boolean | AddEventListenerOptions | undefined): void', gave the following error.
Argument of type '(event: ChangeEvent<Body>) => void' is not assignable to parameter of type '(this: Window, ev: Event) => any'.
Types of parameters 'event' and 'ev' are incompatible.
Type 'Event' is not assignable to type 'ChangeEvent<Body>'.
比我尝试了以下。这编译正确。
useEffect(() => {
const onScroll = (event: Event) => { // <--- changed event type here
console.log("event", event.target);
};
window.addEventListener("scroll", onScroll);
return () => window.removeEventListener("scroll", onScroll);
}, []);
event.target
但是,如果没有编译错误,则无法访问。我检查了以下函数调用(如果我忽略错误,它在浏览器中工作):
useEffect(() => {
const onScroll = (event: Event) => {
console.log(
"event",
event?.target?.activeElement.getBoundingClientRect() // <--- this function call is actually working (ts-ignored it), even if TypeScript throws an error
);
};
window.addEventListener("scroll", onScroll);
return () => window.removeEventListener("scroll", onScroll);
}, []);
投掷
TypeScript error in /home/sirhennihau/Workspace/giphy-search/src/Components/grid.tsx(27,24):
Property 'activeElement' does not exist on type 'EventTarget'. TS2339
25 | console.log(
26 | "event",
> 27 | event?.target?.activeElement.getBoundingClientRect()
| ^
28 | );
29 | };
30 |
我的依赖:
"@types/node": "^12.0.0",
"@types/react": "^16.9.53",
"@types/react-dom": "^17.0.0",
"react": "^17.0.1",
"react-dom": "^17.0.1",
"react-scripts": "4.0.1",
"typescript": "^4.0.3"
也许只是打字不好还是我做错了什么?
解决方案
嗯,是的,React-Events 和 DOM-Events有时不能互相“顺利”,但是有一些干净的方法来处理你的用例(根据我的经验,React 中的大多数用例):
DOM 事件
DOM 方法window.addEventListener
需要一个 DOM- EventListener
(
(evt: Event): void;
),因此您需要使用 DOM-Event
接口(就像您所做的那样)。
在这里,我在您的代码中添加了一些类型来说明这一点:
useEffect(() => {
const onScroll: EventListener = (event: Event) => { // <-- DOM-EventListener
console.log("event", event.target);
};
const win: Window = window; // <-- DOM-Window, extends DOM-EventTarget
win.addEventListener("scroll", onScroll);
return () => window.removeEventListener("scroll", onScroll);
}, []);
event.target
event.target
应该是可访问的。我假设您的意思是如果您尝试访问会出现错误event.target.activeElement
。
event.target.activeElement
抛出错误,因为Event
可能是任何事件,
event.target
可能是任何扩展的元素EventTarget | null
,它不是特定元素,也可能没有activeElement
.
但尽管存在 TS 错误,它仍然有效,因为实际上它是一个具有.activeElement
.
const onScroll: EventListener = (event: Event) => {
const targetAny: EventTarget | null = event.target; // <-- maybe has no .activeElement
console.log( targetAny.activeElement );
};
如果您确定元素是什么,您可以键入断言 特定元素:
const onScroll: EventListener = (event: Event) => {
const targetDiv: HTMLDocument = event.target as HTMLDocument; // <-- assert DOM-HTMLDocument
console.log("DOM event", targetDiv.activeElement); // <-- activeElement works
};
反应事件
React-Types 应该与 React-Elements 一起使用。
您仍然必须声明of 的类型event.target
才能访问特定元素的属性(这里我使用.style
),因为.target
(React.SyntheticEvent
扩展的)的 DOM-与 DOM-使用React.BaseSyntheticEvent
的完全相同。EventTarget
Event
需要明确的是:是的,React 也使用了一些 DOM-Types,所以这里 React 使用 DOM-Events “进展顺利”。
const onScrollReact: React.EventHandler<React.UIEvent<ReactNode>> = (event: React.UIEvent<React.ReactNode> ) => {
const target: EventTarget = event.target; // <-- React uses the DOM EventTarget
const targetDiv: HTMLDivElement = target as HTMLDivElement; // <-- type assert DOM-HTMLDivElement
console.log("React event", target.style); // <-- throws TS error
console.log("React event", targetDiv.style); // <-- no TS error
};
return (<div
onScroll={ onScrollReact }
style={{ height: '400px', overflow: 'scroll' }}
>
<div style={{ height: '2000px', backgroundColor: '#eee' }}>
try scroll event
</div>
</div>);
您也可以在本例中使用 DOM- HTMLDivElement
(行为完全相同,但我猜它更具“声明性”):
const onScrollReact2: React.EventHandler<React.UIEvent<HTMLDivElement>> = (event: React.UIEvent<HTMLDivElement>) => {
console.log("React event", event.target.style); // <-- still throws TS error
};
推荐阅读
- python - 布尔值总是返回为真?(熊猫)
- python - 在 NVIDIA Jetson TX2 上运行的 ultralytics yolov5 的非法指令(核心转储)
- javascript - 如何在“按Enter”jquery php上传递参数
- excel - Excel 文本连接:从重复的列值中提取单元格值
- python - Pytest如何对需要雪花连接的函数返回数据帧进行测试?
- clion - 在 clion 中使用编译数据库
- php - 烦人的重定向阻止我在本地主机上使用 WordPress 仪表板
- python - 将数据从一个 Kafka 主题移动到另一个主题在 Kafka Python 中不起作用
- jmeter - 在 JMeter 中保持负载是什么意思
- c - 为什么我的 yes(Y) 不起作用但我的 no(N) 起作用