使用TypeScript的React事件处理程序

627 阅读3分钟

在这篇文章中,我们将介绍如何用TypeScript实现具有强类型参数的React事件处理程序。

Strongly-typed React Events React事件类型

React事件系统是浏览器本地事件系统的一个包装。这个事件系统的TypeScript类型可以在 @types/reactnpm包中。这些类型可以用于强类型的事件参数。一些常见的是:

  • ChangeEvent<T>
  • KeyboardEvent<T>
  • MouseEvent<T>
  • FormEvent<T>

这些类型都是由SyntheticEvent<T>

所有的事件类型都是通用的,并且接受引发事件的元素的类型。例如,MouseEvent<HTMLButtonElement> 可以用于按钮点击处理程序的参数类型。

内联事件处理程序

如果事件处理程序是在JSX元素中内联实现的,它将自动被强类型化。考虑一下下面的例子:

<input
  type="text"
  value={criteria}
  onChange={(e) =>
    setCriteria(e.currentTarget.value)
  }
/>

TypeScript能够推断出e 的类型,即ChangeEvent<HTMLInputElement> 。因此,当我们引用e ,我们会得到很好的自动完成:

Inline handler autocomplete

🏃玩转代码

命名的事件处理程序

当事件处理程序使用一个命名的函数时,类型的选择就比较麻烦了。考虑一下下面的例子:

function Searchbox() {
  const [criteria, setCriteria] = React.useState(
    ""
  );
  const handleChange = (e) => {    setCriteria(e.currentTarget.value);  };  return (
    <input
      type="text"
      value={criteria}
      onChange={handleChange}
    />
  );
}

TypeScript推断handleChangee 参数的类型为any 。因此,当e 在处理程序的实现中被引用时,将不会发生类型检查。

这可不妙!

我们可以使用一个类型注解来明确定义e 的类型。e 应该被设置成什么类型?好吧,一个巧妙的提示是将鼠标悬停在事件处理程序道具上以找出答案。

Hover tip 所以,类型是ChangeEvent<HTMLInputElement> 。所以,一个强类型的handleChange 事件处理程序的版本如下:

const handleChange = (
  e: React.ChangeEvent<HTMLInputElement>) => {
  setCriteria(e.currentTarget.value);
};

很好!

🏃播放代码

跨元素事件处理程序

处理来自多个元素的事件的事件处理程序如何?考虑一下下面的例子:

const handleChange = (fieldName: string) => (e) => {  ...};
return (
  ...
  <input
    type="text"
    placeholder="Enter your name"
    value={values.name}
    onChange={handleChange("name")}  />
  <textarea
    placeholder="Enter some notes"
    value={values.notes}
    onChange={handleChange("notes")}  />
  ...
);

事件处理程序中的e 参数目前是any 的类型。

我们可以将ChangeEvent 类型用于e ,但我们将什么元素类型传入这个通用类型?事件处理程序正在处理两个不同元素的事件 -HTMLInputElementHTMLTextAreaElement 。我们可以为这些元素使用联合类型,HTMLInputElement | HTMLTextAreaElement 。所以,一个强类型的事件处理程序是这样的:

const handleChange = (fieldName: string) => (
  e: React.ChangeEvent<    HTMLInputElement | HTMLTextAreaElement  >) => {
  ...
};

如果我们有一个用于所有字段值的类型,我们也可以缩小fieldName 的类型。在这个例子中,values 的类型是:

type NameAndNotes = {
  name: string;
  notes: string;
};

所以,我们可以用keyof 关键字来改进fieldName 的类型,如下所示:

const handleChange = (fieldName: keyof NameAndNotes) => ( ... ) => ...

整洁!

🏃播放代码

结束语

React的标准事件类型可在@types/react 。这包括通用类型,可以通过传递引发事件的元素的类型,用于强类型的事件处理参数。

TypeScript可以推断出内联事件处理程序的参数类型。我们需要在一个命名的事件处理程序中明确地对参数使用一个类型注释。我们可以悬停在事件处理程序道具上,发现处理程序的参数类型应该是什么。