A Cheatheet React TypeScript – Como configurar tipos em ganchos

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>
  );
}

Para definir tipos no useState gancho, você precisa passar para <> o tipo do estado. Você também pode usar um tipo de união como este <number | null> se você não tiver um estado inicial.

Definir tipos em usoRef

o useRef hook retorna um objeto ref mutável que permite acessar elementos 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>
  );
}

Como você pode ver, o caminho useRef recebe tipos é o mesmo que o useState gancho. Você só precisa passar para o <>. E, se você tiver várias anotações de tipo, use o tipo de união como eu faço aqui.

Definir tipos em useContext

useContext é um gancho que permite acessar e consumir um determinado contexto em um aplicativo 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>
  );
}

Aqui, começamos criando o IArticle interface que é o tipo do nosso contexto.
Em seguida, usamos no createContext() método para criar um novo contexto e, em seguida, inicialize-o com []. Você também pode usar null como um estado inicial, se desejar.

Com isso, agora podemos lidar com o estado do contexto e definir o tipo como useContext para esperar uma matriz do tipo IArticle como um valor.

Definir tipos em uso

o useReducer hook ajuda a gerenciar estados mais complexos. É uma alternativa para useState – mas lembre-se de que eles são diferentes.

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>
  );
}

Aqui, começamos declarando os tipos de ação que permitem manipular o contador. Em seguida, definimos dois tipos para a função redutora e o estado do contador, respectivamente.

O redutor espera uma state do tipo ICounter e um action do tipo IReducer. Com isso, o contador agora pode ser manipulado.

o useReducer gancho recebe a função redutora e um estado inicial como argumentos e retorna dois elementos: o state do balcão e do dispatch açao.

Para definir o tipo para os valores retornados por ueReducer, basta passar para o <> o tipo de seus dados.

Com isso, o contador agora pode ser incrementado ou diminuído por meio de useReducer.

Definir tipos em useMemo

o useMemo O gancho permite memorizar a saída de uma determinada função. Retorna um valor memorizado.

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

Para definir tipos em useMemo, basta passar para o <> o tipo de dados que você deseja memorizar. Aqui, o gancho espera um string como um valor retornado.

Definir tipos em uso

o useCallback O gancho permite memorizar uma função para evitar renderizações desnecessárias. Retorna um retorno de chamada memorizado.

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

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

Aqui, declaramos o CallbackType tipo que está usando como tipo no retorno de chamada que queremos memorizar.

Ele espera receber parâmetros do tipo string e deve retornar um valor do tipo void.

Em seguida, definimos esse tipo como useCallback – e se você passar um tipo errado para o retorno de chamada ou a matriz de dependências, o TypeScript gritará com você.

Você pode encontrar outros ótimos conteúdos como este em meu blog ou me siga no Twitter para ser notificado.

Obrigado pela leitura.