Aide-mémoire React TypeScript - Comment définir les types sur les Hooks

Aug 04, 2020 6 min Follow me on Twitter

Subscribe to receive the free weekly article

TypeScript est un excellent langage qui permet de vérifier le type de votre code afin de le rendre plus robuste et compréhensible.

Dans ce guide, je vais vous expliquer comment définir les types TypeScript sur les Hooks de React JS comme useState, useContext, useCallback, etc.

Allons-y

Définir les types sur useState

Le hook useState vous permet de gérer l'état dans votre application React. C'est l'équivalent de this.state dans un composant de classe.

import * as React from "react"

export const App: React.FC = () => {
  const [counter, setCounter] = React.useState<number>(0)

  return (
    <div className="App">
      <h1>Result: {counter}</h1>
      <button onClick={() => setCounter(counter + 1)}>+</button>
      <button onClick={() => setCounter(counter - 1)}>-</button>
    </div>
  )
}

Pour définir des types sur le hook useState, vous devez passer dans <> le type de l'état. Vous pouvez également utiliser le type d'union comme ceci <nombre | null> si vous n'avez pas défini un état initial.

Définir les types sur useRef

Le hook useRef retourne un objet ref mutable qui permet d'accéder aux éléments DOM.

import * as React from "react"

export const App: React.FC = () => {
  const myRef = React.useRef<HTMLElement | null>(null)

  return (
    <main className="App" ref={myRef}>
      <h1>My title</h1>
    </main>
  )
}

Comme vous pouvez le voir, la façon dont useRef reçoit les types est la même que le hook useState. Vous devez juste le passer dans le <>; et, si vous avez plusieurs annotations de type, utilisez simplement le type union comme je le fais ici.

Définir les types sur useContext

useContext est un hook qui permet d'accéder et de consommer un contexte donné dans une application React.

import * as React from "react"

interface IArticle {
  id: number
  title: string
}

const ArticleContext = React.createContext<IArticle[] | []>([])

const ArticleProvider: React.FC<React.ReactNode> = ({ children }) => {
  const [articles, setArticles] = React.useState<IArticle[] | []>([
    { id: 1, title: "post 1" },
    { id: 2, title: "post 2" },
  ])

  return (
    <ArticleContext.Provider value={{ articles }}>
      {children}
    </ArticleContext.Provider>
  )
}

const ShowArticles: React.FC = () => {
  const { articles } = React.useContext<IArticle[]>(ArticleContext)

  return (
    <div>
      {articles.map((article: IArticle) => (
        <p key={article.id}>{article.title}</p>
      ))}
    </div>
  )
}

export const App: React.FC = () => {
  return (
    <ArticleProvider>
      <h1>My title</h1>
      <ShowArticles />
    </ArticleProvider>
  )
}

Ici, nous commençons par créer l'interface IArticle qui est le type de notre contexte. Ensuite, nous l'utilisons sur la méthode createContext() pour créer un nouveau contexte, puis l'initialisons avec []; vous pouvez également utiliser null comme état initial si vous le souhaitez aussi.

Avec cela en place, nous pouvons maintenant gérer l'état du contexte et définir le type sur useContext afin d'attendre un tableau de type IArticle comme valeur.

Définir les types sur useReducer

Le hook useReducer permet de gérer des états plus complexes. C'est une alternative à useState; mais gardez à l'esprit qu'ils sont différents.

import * as React from "react"

enum ActionType {
  INCREMENT_COUNTER = "INCREMENT_COUNTER",
  DECREMENT_COUNTER = "DECREMENT_COUNTER",
}

interface IReducer {
  type: ActionType
  count: number
}

interface ICounter {
  result: number
}

const initialState: ICounter = {
  result: 0,
}

const countValue: number = 1

const reducer: React.Reducer<ICounter, IReducer> = (state, action) => {
  switch (action.type) {
    case ActionType.INCREMENT_COUNTER:
      return { result: state.result + action.count }
    case ActionType.DECREMENT_COUNTER:
      return { result: state.result - action.count }
    default:
      return state
  }
}

export default function App() {
  const [state, dispatch] = React.useReducer<React.Reducer<ICounter, IReducer>>(
    reducer,
    initialState
  )

  return (
    <div className="App">
      <h1>Result: {state.result}</h1>
      <button
        onClick={() =>
          dispatch({ type: ActionType.INCREMENT_COUNTER, count: countValue })
        }
      >
        {" "}
        +
      </button>
      <button
        onClick={() =>
          dispatch({ type: ActionType.DECREMENT_COUNTER, count: countValue })
        }
      >
        {" "}
        -
      </button>
    </div>
  )
}

Ici, nous commençons par déclarer les types d'actions qui permettent de gérer le compteur. Ensuite, nous définissons respectivement deux types pour la fonction de réduction et l'état du compteur.

Le réducteur attend un state de type ICounter et une action de type IReducer. Avec cela, le compteur peut maintenant être manipulé en conséquence.

Le hook useReducer reçoit la fonction de réduction et un état initial comme arguments et retourne deux éléments: le state du compteur et l'action dispatch.

Pour définir le type des valeurs renvoyées par ueReducer, passez simplement dans <> le type de vos données.

Avec cela en place, le compteur peut maintenant être incrémenté ou décrémenté via useReducer.

Définir les types sur useMemo

Le hook useMemo vous permet de mémoriser la sortie d'une fonction donnée. Il renvoie une valeur mémorisée.

const memoizedValue = React.useMemo<string>(() => {
  computeExpensiveValue(a, b)
}, [a, b])

Pour définir des types sur useMemo, passez simplement dans <> le type de données que vous souhaitez mémoriser. Ici, le hook attend un string comme valeur renvoyée.

Définir les types lors de l'utilisationCallback

Le hook useCallback vous permet de mémoriser une fonction pour éviter des rendus inutiles. Il renvoie un callback mémorisé.

type CallbackType = (...args: string[]) => void

const memoizedCallback = React.useCallback<CallbackType>(() => {
  doSomething(a, b)
}, [a, b])

Ici, nous déclarons le type CallbackType qui est utilisé comme type sur le callback que nous voulons mémoriser.

Il s'attend à recevoir des paramètres de type string et doit renvoyer une valeur de type void.

Ensuite, nous définissons ce type sur useCallback - et si vous passez un mauvais type au callback ou au tableau de dépendances - TypeScript vous criera dessus.

Merci d'avoir lu

#typescript#react#hooks

Support my work

Get articles in your inbox