React+TypeScript中的事件类型

本文参考了 Matt Pocock 的文章 Event Types in React and TypeScript ,有条件的可以阅读英文原版。

一、前言

用 React 和 TypeScript 开发时,会经常碰到这个报错:

当我们给不同的 DOM 元素添加事件处理函数时,onChange 中参数 e 接收到的事件类型是不同的,我们必须为e 指定正确的类型。

二、解决方案

1. 鼠标悬浮

我们把鼠标悬浮在 onChange 上,IDE 会给出相应的类型,直接复制,再将类型添加给声明的事件处理函数:
我们需要的是 ?: 后面的这部分代码。

2. 内联函数

当我们只想为 e 添加类型时,首先要知道 e 的类型是什么。

创建一个内联事件处理函数,将鼠标悬浮在参数 e 上,IDE 会给出正确的类型,选中并复制:

然后添加到我们的处理函数中:

3. 使用 React.ComponentProps

React.ComponentProps 是一个类型工具,用于获取组件或元素的类型。

4. EventFor 工具类型

第三种方案非常方便,但是如果我们只是想给 e 添加类型,有没有更优雅的写法呢?

我们可以用 TypeScript 内置的工具类型 ParametersNonNullable 以及索引访问来实现:

解释一下上面的代码:

  • React.ComponentProps<'input'>['onChange'] 在第三种方案中用过,但是这个类型包含 undefined ,需要使用 NonNullable 把它去掉;
  • NonNullable 用于去除某个类型中的 nullundefined
  • Parameters 用于获取某个函数的所有参数类型,返回一个类型数组,再使用 [0] 取出第一个参数的类型。

如此一来,我们就拿到了参数 e 的正确类型。

但是,上面这种写法有点冗杂,我们可以再进一步,封装一个工具类型:

typescript 复制代码
type GetEventHandlers<
  T extends keyof JSX.IntrinsicElements,
> = Extract<keyof JSX.IntrinsicElements[T], `on${string}`>

type EventFor<
  TElement extends keyof JSX.IntrinsicElements,
  THandler extends GetEventHandlers<TElement>,
> = JSX.IntrinsicElements[TElement][THandler] extends
  | (((e: infer TEvent) => any) | undefined)
  ? TEvent
  : never

上面这段代码需要一些类型体操的知识,这里只解释大概原理:

  • JSX.IntrinsicElements 是一个 interface ,其中声明了所有 HTML 元素的类型;

  • GetEventHandlers 接收一个元素类型,通过 Extract 提取该元素所有 onXxxx 形式的属性,也就是所有的事件:

  • EventFor 接收两个泛型,分别代表元素类型和事件名称,根据这两个泛型从 JSX.IntrinsicElements 中取出对应事件的处理函数的类型声明,然后通过 extends 以及 infer 关键字推断参数 e 的类型并返回。

效果:

相关推荐
Setsuna_F_Seiei2 分钟前
前端转型 Agent 开发 05 之 Agent Hooks 与 Checkpointer(让 Agent 从全自动转变人为可掌控)
前端·agent·ai编程
百万蹄蹄向前冲2 小时前
风扇转了一晚上MVP专家团翻车事故
前端·人工智能
默_笙2 小时前
🏛 给 AI 配一间办公室:Harness Engineering 六大模块与它的实现
前端·javascript
linux_cfan3 小时前
videojs v10 源代码系列解读:14 · 谓词守卫:在运行时安全地调用能力
前端·javascript·音视频
狗狗狗狗狗乐啊3 小时前
搭一个 AI 对话工作台 AChat:从 0 到可用的完整记录(一)
python·react.js·ai编程
kyriewen4 小时前
我扒了 10,221 条 JD:腾讯技术岗 75% 在要 AI
前端·人工智能·ai编程
郑州光合科技余经理4 小时前
同城外卖小程序开发:下单成功后,后台导出能不能对上用户端状态
开发语言·前端·git·后端·uni-app·php·ai编程
IT_陈寒5 小时前
Vue的响应式让我熬到凌晨三点,原来漏了这个小细节
前端·人工智能·后端
Blanche15005 小时前
利用 RAG 为答疑机器人扩展知识范围
前端
天若有情6735 小时前
【纯前端小工具】公历生日转农历,批量查询每年农历生日对应的公历日期(GitHub Pages在线直接用)
前端·javascript·github pages·农历转换·lunisolar·网页小工具