焦慮可分為有用焦慮和無用焦慮兩種。
- 有用焦慮指向現(xiàn)在
- 無用焦慮指向未來,它的本質(zhì),是對(duì)現(xiàn)在失控的恐懼
大家好,我是柒八九。
今天還是--TypeScript實(shí)戰(zhàn)系列的文章。前面的文章中,我們從不同的角度介紹了,TS是如何結(jié)合React進(jìn)行項(xiàng)目開發(fā)的。相關(guān)文章如下。
而今天我們主要是講如何利用TS對(duì)React中的事件回調(diào)進(jìn)行類型化處理。
好了,天不早了。我們開始粗發(fā)。

1. 示例代碼
這是一個(gè)非常簡(jiǎn)單的React應(yīng)用,有一個(gè)input和一個(gè)button。我們用這個(gè)例子來一步步處理,如何用TS處理里面的事件回調(diào)。
import { useState } from 'react';
export default function App() {
const [inputValue, setInputValue] = useState('');
const handleInputChange = (event) => {
setInputValue(event.target.value);
};
const handleClick = (event) => {
console.log('提交被觸發(fā)');
};
return (
<div className="App">
<h1>前端柒八九</h1>
<input value={inputValue} onChange={handleInputChange} />
<button onClick={handleClick}>提交</button>
</div>
);
}
2. 添加TS
有幾種方法來類型化上述代碼中的回調(diào)函數(shù),我們將看到3種主要的方法。
- 類型化事件處理程序的參數(shù)
- 類型化事件處理程序本身
- 依靠類型推斷
類型化事件處理程序的參數(shù)(event)
先處理onClick事件。React 提供了一個(gè) MouseEvent 類型,可以直接使用!
import {
useState,
+ MouseEvent,
} from 'react';
export default function App() {
// 省略部分代碼
+ const handleClick = (event: MouseEvent) => {
console.log('提交被觸發(fā)');
};
return (
<div className="App">
<h1>前端柒八九</h1>
<button onClick={handleClick}>提交</button>
</div>
);
}
onClick事件實(shí)際上是由React維護(hù)的:它是一個(gè)合成事件。
合成事件是React對(duì)瀏覽器事件的一種包裝,以便不同的瀏覽器,都有相同的API。
handleInputChange函數(shù)與 handleClick 非常相似,但有一個(gè)明顯的區(qū)別。不同的是,ChangeEvent 是一個(gè)泛型,你必須提供什么樣的DOM元素正在被使用。
import {
useState,
+ ChangeEvent
} from 'react';
export default function App() {
const [inputValue, setInputValue] = useState('');
+ const handleInputChange = (event: ChangeEvent<HTMLInputElement>) => {
setInputValue(event.target.value);
};
// 省略部分代碼
return (
<div className="App">
<h1>前端柒八九</h1>
<input value={inputValue} onChange={handleInputChange} />
</div>
);
}
在上面的代碼中需要注意的一點(diǎn)是,HTMLInputElement 特指HTML的輸入標(biāo)簽。如果我們使用的是 textarea,我們將使用 HTMLTextAreaElement 來代替。
注意,MouseEvent 也是一個(gè)泛型,你可以在必要時(shí)對(duì)它進(jìn)行限制。例如,讓我們把上面的 MouseEvent 限制為專門從一個(gè)按鈕發(fā)出的鼠標(biāo)事件。
const handleClick = (event: MouseEvent<HTMLButtonElement>) => {
console.log('提交被觸發(fā)');
};
還需要提示的是,React為我們提供了很多 Event 對(duì)象的類型聲明。
Event 事件對(duì)象類型
| 事件類型 | 解釋 |
|---|---|
ClipboardEvent<T = Element> |
剪切板事件對(duì)象 |
DragEvent<T =Element> |
拖拽事件對(duì)象 |
ChangeEvent<T = Element> |
Change事件對(duì)象 |
KeyboardEvent<T = Element> |
鍵盤事件對(duì)象 |
MouseEvent<T = Element> |
鼠標(biāo)事件對(duì)象 |
TouchEvent<T = Element> |
觸摸事件對(duì)象 |
WheelEvent<T = Element> |
滾輪時(shí)間對(duì)象 |
AnimationEvent<T = Element> |
動(dòng)畫事件對(duì)象 |
TransitionEvent<T = Element> |
過渡事件對(duì)象 |
類型化事件處理程序本身
React 聲明文件所提供的 EventHandler 類型別名,通過不同事件的 EventHandler 的類型別名來定義事件處理函數(shù)的類型,更方便定義其函數(shù)類型。

type EventHandler<E extends SyntheticEvent<any>> = {
bivarianceHack(event: E): void
}['bivarianceHack']
bivarianceHack 為事件處理函數(shù)的類型定義,函數(shù)接收一個(gè) event 對(duì)象,并且其類型為接收到的泛型變量 E 的類型, 返回值為 void。
而在類型定義的時(shí)候,有一個(gè)很怪異的行為['bivarianceHack']。
這與 strictfunctionTypes 下的功能兼容性有關(guān)。在此選項(xiàng)下,如果參數(shù)是派生類型,則不能將其傳遞給將傳入基類參數(shù)的函數(shù)。例如:
class Animal { private x:undefined }
class Dog extends Animal { private d: undefined }
type EventHandler<E extends Animal> = (event: E) => void
let o: EventHandler<Animal> = (o: Dog) => { } // 在 strictFunctionTypes 模式下,失敗
此時(shí),TS會(huì)報(bào)警告。
所以hack的作用是即使在 strictFunctionTypes啟用的情況下允許EventHandler的二元行為。 由于事件處理程序的簽名將在方法聲明中有其來源,因此它不會(huì)受到更嚴(yán)格的函數(shù)檢查。
type BivariantEventHandler<E extends Animal> = { bivarianceHack(event: E): void }["bivarianceHack"];
// 在 strictFunctionTypes 模式下,生效
let o2: BivariantEventHandler<Animal> = (o: Dog) => { }
講的有點(diǎn)多,我們還是繞回本文的重點(diǎn)。使用EventHandler來對(duì)上面的例子進(jìn)行改造處理。
import {
useState,
+ ChangeEventHandler,
+ MouseEventHandler
} from 'react';
export default function App() {
const [inputValue, setInputValue] = useState('');
+ const handleInputChange: ChangeEventHandler<HTMLInputElement> = (event) =>{
setInputValue(event.target.value);
};
+ const handleClick: MouseEventHandler = (event) => {
console.log('提交被觸發(fā)');
};
return (
// ...省略....
);
}
系不系,很簡(jiǎn)單。
依賴類型推斷
你也可以依靠類型推斷,而不需要自己處理函數(shù)。但是,你需要將回調(diào)函數(shù)內(nèi)聯(lián)處理。
import { useState } from 'react';
export default function App() {
const [inputValue, setInputValue] = useState('');
return (
<div className="App">
<h1>前端柒八九</h1>
<input
value={inputValue}
+ onChange={(event) => setInputValue(event.target.value)}
/>
<button
+ onClick={(event) => console.log('提交被觸發(fā)')}
>
提交
</button>
</div>
);
}
這個(gè)更簡(jiǎn)單
后記
分享是一種態(tài)度。
參考資料:
全文完,既然看到這里了,如果覺得不錯(cuò),隨手點(diǎn)個(gè)贊和“在看”吧。

本文由mdnice多平臺(tái)發(fā)布