首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >not + TypeScript:滚动事件类型不能分配给window.addEventListener

not + TypeScript:滚动事件类型不能分配给window.addEventListener
EN

Stack Overflow用户
提问于 2021-01-01 15:10:31
回答 1查看 13.8K关注 0票数 12

事件和反应事件类型的TypeScript DOM类型可能与另一个事件类型不太匹配吗?

看看这段代码:

代码语言:javascript
运行
复制
  useEffect(() => {
    const onScroll = (event: React.ChangeEvent<Body>) => {
      console.log("event", event.target);
    };

    window.addEventListener("scroll", onScroll);

    return () => window.removeEventListener("scroll", onScroll);
  }, []);

它抛出

代码语言:javascript
运行
复制
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>'.

比我试过的更好。这将正确编译。

代码语言:javascript
运行
复制
  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不能在没有编译错误的情况下进行访问。我检查了以下函数调用(如果它在浏览器中工作-忽略错误):

代码语言:javascript
运行
复制
  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);
  }, []);

抛出

代码语言:javascript
运行
复制
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 |

我的依赖关系:

代码语言:javascript
运行
复制
    "@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"

也许只是打字不好还是我做错了什么?

EN

回答 1

Stack Overflow用户

发布于 2021-01-08 00:22:43

嗯,是的,React -事件和DOM--事件有时不能“很好地”处理彼此,但是有一些处理用例的干净方法(在我的经验中,最重要的是React中的用例):

DOM事件

DOM window.addEventListener需要一个DOM-EventListener ( (evt: Event): void;),因此您需要使用DOM-Event接口(就像您所做的那样)。

在这里,我向代码中添加了一些类型,以说明以下内容:

代码语言:javascript
运行
复制
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的元素。

代码语言:javascript
运行
复制
const onScroll: EventListener = (event: Event) => {
    const targetAny: EventTarget | null = event.target; // <-- maybe has no .activeElement
    console.log( targetAny.activeElement );
};

如果您确定该元素是什么,则可以类型断言特定的元素:

代码语言:javascript
运行
复制
const onScroll: EventListener = (event: Event) => {
    const targetDiv: HTMLDocument = event.target as HTMLDocument; // <-- assert DOM-HTMLDocument
    console.log("DOM event", targetDiv.activeElement);    // <-- activeElement works
};

反应事件

反应类型应与反应元素一起使用.

您的仍然需要断言类型的event.target才能访问特定元素的属性(这里我使用.style),因为React.SyntheticEvent.target (扩展React.BaseSyntheticEvent)与DOM-Event使用的DOM-EventTarget完全相同。

明确一点:是的,React也使用了一些DOM类型,所以这里用DOM事件做出反应“很好”。

代码语言:javascript
运行
复制
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 (行为完全相同,但更多的是“声明性”,我猜):

代码语言:javascript
运行
复制
const onScrollReact2: React.EventHandler<React.UIEvent<HTMLDivElement>> = (event: React.UIEvent<HTMLDivElement>) => {
    console.log("React event", event.target.style); // <-- still throws TS error
};
票数 7
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/65530852

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档