React項目中應用TypeScript
- 2021 年 9 月 16 日
- 筆記
- typescript
一、前言
單獨的使用typescript
並不會導致學習成本很高,但是絕大部分前端開發者的項目都是依賴於框架的
例如和vue
、react
這些框架結合使用的時候,會有一定的門檻
使用 TypeScript
編寫 react
程式碼,除了需要 typescript
這個庫之外,還需要安裝@types/react
、@types/react-dom
npm i @types/react -s
npm i @types/react-dom -s
至於上述使用@types
的庫的原因在於,目前非常多的javascript
庫並沒有提供自己關於 TypeScript
的聲明文件
所以,ts
並不知道這些庫的類型以及對應導出的內容,這裡@types
實際就是社區中的DefinitelyTyped
庫,定義了目前市面上絕大多數的JavaScript
庫的聲明
所以下載相關的javascript
對應的@types
聲明時,就能夠使用使用該庫對應的類型定義
二、使用方式
在編寫react
項目的時候,最常見的使用的組件就是:
- 無狀態組件
- 有狀態組件
- 受控組件
無狀態組件
主要作用是用於展示UI
,如果使用js
聲明,則如下所示:
import * as React from 'react'
export const Logo = props => {
const { logo, className, alt } = props
return (
<img src={logo} className={className} alt={alt} />
)
}
但這時候ts
會出現報錯提示,原因在於沒有定義porps
類型,這時候就可以使用interface
介面去定義porps
即可,如下:
import * as React from 'react'
interface IProps {
logo?: string
className?: string
alt?: string
}
export const Logo = (props: IProps) => {
const { logo, className, alt } = props
return (
<img src={logo} className={className} alt={alt} />
)
}
但是我們都知道props
裡面存在children
屬性,我們不可能每個porps
介面裡面定義多一個children
,如下:
interface IProps {
logo?: string
className?: string
alt?: string
children?: ReactNode
}
更加規範的寫法是使用React
裡面定義好的FC
屬性,裡面已經定義好children
類型,如下:
export const Logo: React.FC<IProps> = props => {
const { logo, className, alt } = props
return (
<img src={logo} className={className} alt={alt} />
)
}
-
React.FC顯式地定義了返回類型,其他方式是隱式推導的
-
React.FC對靜態屬性:displayName、propTypes、defaultProps提供了類型檢查和自動補全
-
React.FC為children提供了隱式的類型(ReactElement | null)
有狀態組件
可以是一個類組件且存在props
和state
屬性
如果使用typescript
聲明則如下所示:
import * as React from 'react'
interface IProps {
color: string,
size?: string,
}
interface IState {
count: number,
}
class App extends React.Component<IProps, IState> {
public state = {
count: 1,
}
public render () {
return (
<div>Hello world</div>
)
}
}
上述通過泛型對props
、state
進行類型定義,然後在使用的時候就可以在編譯器中獲取更好的智慧提示
關於Component
泛型類的定義,可以參考下 React 的類型定義文件 node_modules/@types/react/index.d.ts
,如下所示:
class Component<P, S> {
readonly props: Readonly<{ children?: ReactNode }> & Readonly<P>;
state: Readonly<S>;
}
從上述可以看到,state
屬性也定義了可讀類型,目的是為了防止直接調用this.state
更新狀態
受控組件
受控組件的特性在於元素的內容通過組件的狀態state
進行控制
由於組件內部的事件是合成事件,不等同於原生事件,
例如一個input
組件修改內部的狀態,常見的定義的時候如下所示:
private updateValue(e: React.ChangeEvent<HTMLInputElement>) {
this.setState({ itemText: e.target.value })
}
常用Event
事件對象類型:
- ClipboardEvent<T = Element> 剪貼板事件對象
- DragEvent<T = Element> 拖拽事件對象
- ChangeEvent<T = Element> Change 事件對象
- KeyboardEvent<T = Element> 鍵盤事件對象
- MouseEvent<T = Element> 滑鼠事件對象
- TouchEvent<T = Element> 觸摸事件對象
- WheelEvent<T = Element> 滾輪事件對象
- AnimationEvent<T = Element> 動畫事件對象
- TransitionEvent<T = Element> 過渡事件對象
T
接收一個DOM
元素類型
三、總結
上述只是簡單的在react
項目使用typescript
,但在編寫react
項目的時候,還存在hooks
、默認參數、以及store
等等……
typescript
在框架中使用的學習成本相對會更高,需要不斷編寫才能熟練