React專案中應用TypeScript

喆星高照發表於2021-09-16

 

 

一、前言

單獨的使用typescript 並不會導致學習成本很高,但是絕大部分前端開發者的專案都是依賴於框架的

例如和vuereact 這些框架結合使用的時候,會有一定的門檻

使用 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)

有狀態元件

可以是一個類元件且存在propsstate屬性

如果使用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>
    )
  }
}

上述通過泛型對propsstate進行型別定義,然後在使用的時候就可以在編譯器中獲取更好的智慧提示

關於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在框架中使用的學習成本相對會更高,需要不斷編寫才能熟練

相關文章