Definitelytyped: 使 React.SyntheticEvent.target 在 T 上通用,而不是 React.SyntheticEvent.currentTarget

创建于 2016-09-26  ·  7评论  ·  资料来源: DefinitelyTyped/DefinitelyTyped

目前,React 的SyntheticEvent的 Typescript 2.0 签名如下所示:

interface SyntheticEvent<T> {
    currentTarget: EventTarget & T;
    target: EventTarget;
}

根据提交 a13fa7abf55daedf25b31258b908548f55962c7a, target最初是EventTarget & T ,但此更改(显然)在提交 5607f54defce88bc52a0f453422.c 的合并期间意外恢复

当前的签名破坏了很多 2.0 之前的代码(你可以想象,React 代码充满了事件处理程序),但几乎没有任何好处(因为大多数代码依赖于event.target ,所以这意味着仍然依赖于 pre -2.0 代码像(event.target as any).value ,因为event.target不是通用的。

我很乐意提供补丁,但我想确保SyntheticEvent.target不是故意去通用化的。

最有用的评论

你不能总是在编译时告诉目标的类型。 使它成为通用的价值不大。
target 是事件的起源(没有人真正关心它,例如它可能是链接内的一个跨度)
currentTarget 是附加了事件处理程序的元素,如果您将数据集或其他属性附加到它并打算在运行时访问,您应该非常关心并相应地键入。

依赖 target 而不是 currentTarget 是初学者的错误,它会比后者更快地咬住他们。

例如:

  handleTabClick = (e: React.SyntheticEvent<HTMLLinkElement>) => {
    e.preventDefault()
    // !!! e.target.dataset is empty if user clicked the <span>, not the <a> !!!
    // !!! how can you type e.target? User might also have clicked the <a> if it has padding !!!
    // you have to use currentTarget, and it is the element that you know the type for sure
    if (e.currentTarget.dataset['closable'] === 'true') {
      this.close()
    }
  }

render() {
  return <a onClick={this.handleTabClick} data-closable="true">
      <span className="fatty">Click me!</span>
   </a>
}

此代码用于编译,因为它应该。

合并“修复”后, e.currentTarget不可打字(如果没有类型错误,我无法访问其数据集)并且e.target现在被输入为 HTMLLinkElement,而实际上没有办法我们可以肯定。 (我可能点击了里面的跨度。

从理论上讲,我们可以在 SyntheticEvent 中添加第二个泛型,以键入目标,当用户对其确定时(事件处理程序没有子项,或者它们都具有相同的类型)。 但它没有什么价值,而且确实具有误导性(因为它仅适用于使用强制转换会更有意义的特定情况)。
特别是,如果您没有孩子,则可以使用 currentTarget。

所有7条评论

这可能是合并过程中犯的错误。 请做公关。

参见 #11041、#10784 等等。 为什么即使在合并后它也没有修复是一个谜。

你不能总是在编译时告诉目标的类型。 使它成为通用的价值不大。
target 是事件的起源(没有人真正关心它,例如它可能是链接内的一个跨度)
currentTarget 是附加了事件处理程序的元素,如果您将数据集或其他属性附加到它并打算在运行时访问,您应该非常关心并相应地键入。

依赖 target 而不是 currentTarget 是初学者的错误,它会比后者更快地咬住他们。

例如:

  handleTabClick = (e: React.SyntheticEvent<HTMLLinkElement>) => {
    e.preventDefault()
    // !!! e.target.dataset is empty if user clicked the <span>, not the <a> !!!
    // !!! how can you type e.target? User might also have clicked the <a> if it has padding !!!
    // you have to use currentTarget, and it is the element that you know the type for sure
    if (e.currentTarget.dataset['closable'] === 'true') {
      this.close()
    }
  }

render() {
  return <a onClick={this.handleTabClick} data-closable="true">
      <span className="fatty">Click me!</span>
   </a>
}

此代码用于编译,因为它应该。

合并“修复”后, e.currentTarget不可打字(如果没有类型错误,我无法访问其数据集)并且e.target现在被输入为 HTMLLinkElement,而实际上没有办法我们可以肯定。 (我可能点击了里面的跨度。

从理论上讲,我们可以在 SyntheticEvent 中添加第二个泛型,以键入目标,当用户对其确定时(事件处理程序没有子项,或者它们都具有相同的类型)。 但它没有什么价值,而且确实具有误导性(因为它仅适用于使用强制转换会更有意义的特定情况)。
特别是,如果您没有孩子,则可以使用 currentTarget。

另外它是完全错误的,在DOMAttributes<SomeType> ,你得到一个onClickMouseEventHandler<SomeType> ,然后得到EventHandler<MouseEvent<SomeType>>

    interface EventHandler<E extends SyntheticEvent<any>> {
        (event: E): void;
    }

您绝对不能键入与 currentTarget 不同的 target。 onClick 需要一个具有处理事件(又名 currentTarget)作为泛型的事件处理程序。 它不能是别的东西,它不会编译。

@bbenezech

handleTabClick = (e: React.SyntheticEvent<HTMLLinkElement>) => { ... }

我建议改为:

handleTabClick = (e: React.FormEvent<HTMLLinkElement>) => { ... }

您还有ClipboardEvent<T>CompositionEvent<T>DragEvent<T>FocusEvent<T>KeyboardEvent<T> ...
SyntheticEvent 是低级的东西。

@types NPM 存储库中仍然是这样。 关于何时发布的任何更新

这个改回来了。 见#12239。

此页面是否有帮助?
0 / 5 - 0 等级