Skip to content

typescript-cheatsheets/react-pt

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

29 Commits
 
 
 
 
 
 
 
 

Repository files navigation

React+TypeScript Cheatsheets em PortuguĂȘs

react + ts logo

Cheatsheets para desenvolvedores com experiĂȘncia em React que estĂŁo iniciando com TypeScript

Web docs | äž­æ–‡çż»èŻ‘ | Español | Contribute! | Ask!


👋 Este repositĂłrio Ă© mantido por @giseladifini e @swyx. Estamos muito felizes que vocĂȘ quer experimentar React com Typescript! Se vocĂȘ perceber algo de errado ou faltando, por favor abra uma issue! 👍


Todas as dicas de React + TypeScript

  • Cheatsheet BĂĄsico (/README.md) Ă© focado em ajudar desenvolvedores React a começar a usar TS com React apps
    • Foco nas melhores prĂĄticas com exemplos para copiar e colar.
    • Explica alguns tipos bĂĄsicos de uso de TS e configuração ao longo do caminho.
    • Responde Ă s perguntas mais frequentes.
    • NĂŁo cobre a lĂłgica de tipo genĂ©rico em detalhes. Em vez disso, preferimos ensinar tĂ©cnicas de solução de problemas simples para iniciantes.
    • O objetivo Ă© se familiarizar com TS sem precisar aprender muito sobre TS.
  • Cheatsheet Avançado (/AVANÇADO.md) ajuda a mostrar e explicar o uso avançado de tipos genĂ©ricos para pessoas que escrevem utilitĂĄrios/funçÔes/props de renderização/componentes de ordem superior (HOCs) reutilizĂĄveis ​​e bibliotecas TS+React.
    • Possui dicas e truques diversos para usuĂĄrios profissionais.
    • Conselhos para contribuir com DefinitelyTyped.
    • O Objetivo Ă© tirar total vantagem sobre o TypeScript.
  • Cheatsheet de migração (/MIGRANDO.md) ajuda a reunir conselhos para a migração incremental de grandes bases de cĂłdigo de JS ou Flow, de pessoas que jĂĄ fizeram isso.
    • NĂłs nĂŁo tentamos convencer as pessoas a mudar, apenas ajudar as pessoas que jĂĄ decidiram isso.
    • ⚠ Esta Ă© uma nova cheatsheet, toda ajuda Ă© bem-vinda.
  • Cheatsheet de HOCs (/HOC.md) especificamente ensina as pessoas a escrever HOCs com a ajuda de exemplos.
    • Familiaridade com GenĂ©ricos Ă© necessĂĄrio.
    • ⚠ Esta Ă© uma nova cheatsheet, toda a assistĂȘncia Ă© bem-vinda.

Tabela de conteĂșdos da Cheatsheet bĂĄsica

Expandir Tabela de ConteĂșdo

Seção 1: Configuração

Pré-requisitos

  1. Uma boa compreensĂŁo de React.
  2. Familiaridade com os tipos bĂĄsicos de TypeScript ( O guia de 2ality Ă© de grande ajuda. Se vocĂȘ Ă© completamente novato em TypeScript, dĂȘ uma olhada no tutorial de chibicode ).
  3. Ter lido a seção de TypeScript na documentação oficial do React.
  4. Ter lido a seção do React do novo playground de TypeScript ( Opcional: também acompanhar os mais de 40 exemplos na seção de exemplos do playground ).

Este guia sempre assumirĂĄ que vocĂȘ estĂĄ usando a Ășltima versĂŁo de Typescript. Notas para versĂ”es mais antigas usarĂŁo a etiqueta <details>.

Ferramentas iniciais de React + TypeScript

ConfiguraçÔes na nuvem:

ConfiguraçÔes de desenvolvimento local:

  • Next.js: npx create-next-app -e with-typescript irĂĄ criar no seu diretĂłrio atual.
  • Create React App: npx create-react-app name-of-app --template typescript irĂĄ criar em um novo diretĂłrio.
  • Meteor: meteor create --typescript name-of-my-new-typescript-app
  • Ignite para React Native: ignite new myapp
  • TSDX: npx tsdx create mylib para Creating React+TS libraries
Outras ferramentas

Ferramentas menos maduras mas que vale a pena conferir:

  • Vite: npm init vite-app my-react-project --template react-ts (nota - ainda nĂŁo estĂĄ na versĂŁo v1.0, mas Ă© muito rĂĄpida).
  • Snowpack: npx create-snowpack-app my-app --template app-template-react-typescript
  • Docusaurus v2 com suporte a TypeScript
  • Parcel
  • JP Morgan's modular: CRA + TS + Yarn Workspaces toolkit. yarn create modular-react-app <project-name>

Manual de configuração:

Import React

import * as React from 'react';
import * as ReactDOM from 'react-dom';

Este Ă© o caminho mais seguro no futuro para importar React. Se vocĂȘ definir --allowSyntheticDefaultImports (ou adicionar "allowSyntheticDefaultImports": true) em seu tsconfig.json, vocĂȘ poderĂĄ importar como se faz normalmente em jsx:

import React from 'react';
import ReactDOM from 'react-dom';
Explicação

Por que usar allowSyntheticDefaultImports ao invés de esModuleInterop? Daniel Rosenwasser comentou que é melhor para webpack/parcel. Para consultar mais argumentos dessa discussão wmonk/create-react-app-typescript#214

VocĂȘ tambĂ©m deveria verificar a nova documentação do TypeScript para descriçÔes oficiais entre cada flag do compilador!

Seção 2: Primeiros Passos

Componente de Função

Podem ser escritos como funçÔes normais que recebem props como argumento e retornam um elemento JSX.

type AppProps = { message: string }; /* também se pode usar uma interface */
const App = ({ message }: AppProps) => <div>{message}</div>;
Por que `React.FC` Ă© desencorajado? E sobre `React.FunctionComponent` / `React.VoidFunctionComponent`?

VocĂȘ pode ver isso em muitas bases de cĂłdigo React + TypeScript:

const App: React.FunctionComponent<{ message: string }> = ({ message }) => (
  <div>{message}</div>
);

No entanto, o consenso geral hoje Ă© que o uso de React.FunctionComponent (ou a abreviação React.FC) Ă© [desencorajado] (facebook/create-react-app#8177). Isto Ă© um ponto de vista, Ă© claro, mas se vocĂȘ concorda e deseja remover React.FC da sua base de cĂłdigo, vocĂȘ pode usar [este jscodeshift codemod] (https://github.com/gndelia/codemod-replace-react- fc-typescript).

Algumas diferenças da versão de "função normal":

  • React.FunctionComponent Ă© explĂ­cito sobre o tipo de retorno, enquanto a versĂŁo normal da função Ă© implĂ­cita (ou entĂŁo precisa de anotaçÔes adicionais).

  • Fornece verificação de tipos e preenchimento automĂĄtico para propriedades estĂĄticas como displayName, propTypes e defaultProps.

    • Observe que existem alguns problemas conhecidos usando defaultProps com React.FunctionComponent. Consulte [este problema para obter detalhes] (typescript-cheatsheets/react#87). NĂłs mantemos uma seção defaultProps separada para que vocĂȘ tambĂ©m possa consultar.
  • Fornece uma definição implĂ­cita de children (veja abaixo) - no entanto, hĂĄ alguns problemas com o tipo children implĂ­cito (por exemplo, DefinitelyTyped#33006), e Ă© melhor ser explĂ­cito sobre os componentes que consomem children, de qualquer maneira.

const Title: React.FunctionComponent<{ title: string }> = ({
  children,
  title,
}) => <div title={title}>{children}</div>;
Usando `React.VoidFunctionComponent` ou` React.VFC` como alternativa

A partir da versĂŁo [@types/react 16.9.48] (DefinitelyTyped/DefinitelyTyped#46643), vocĂȘ tambĂ©m poderĂĄ usar o tipo React.VoidFunctionComponent ou React.VFC se quiser tipar children explicitamente. Esta Ă© uma solução provisĂłria atĂ© que FunctionComponent nĂŁo aceite nenhum children por padrĂŁo (planejado para @types/react@^18.0.0).

type Props = { foo: string };

// OK agora mas futuramente causarĂĄ erro
const FunctionComponent: React.FunctionComponent<Props> = ({
  foo,
  children,
}: Props) => {
  return (
    <div>
      {foo} {children}
    </div>
  ); // OK
};

// OK agora mas futuramente se tornarĂĄ obsoleto
const VoidFunctionComponent: React.VoidFunctionComponent<Props> = ({
  foo,
  children,
}) => {
  return (
    <div>
      {foo}
      {children}
    </div>
  );
};
- _No futuro_, ele poderĂĄ marcar automaticamente os `props` como `readonly` (somente leitura), embora isso seja um ponto discutĂ­vel se o objeto `props` for desestruturado na lista de parĂąmetros.

Na maioria dos casos, faz pouca diferença qual sintaxe Ă© usada, mas vocĂȘ pode preferir a natureza mais explĂ­cita de React.FunctionComponent.

Problemas menores

Esses padrÔes não são suportados:

** Renderização condicional **

const MyConditionalComponent = ({ shouldRender = false }) =>
  shouldRender ? <div /> : false; // tampouco faça isso em JS
const el = <MyConditionalComponent />; // gera um erro

Isso ocorre porque, devido às limitaçÔes do compilador, os componentes de função não podem retornar nada além de uma expressão JSX ou null, caso contrårio, ele reclama com uma mensagem de erro enigmåtica dizendo que outro tipo não pode ser atribuído ao Elemento.

const MyArrayComponent = () => Array(5).fill(<div />);
const el2 = <MyArrayComponent />; // gera um erro

Array.fill

Infelizmente, apenas anotar o tipo de função nĂŁo vai ajudar, entĂŁo se vocĂȘ realmente precisar retornar outros tipos exĂłticos que o React suporta, serĂĄ necessĂĄrio executar uma declaração de tipo:

const MyArrayComponent = () => (Array(5).fill(<div />) as any) as JSX.Element;

[Veja o comentĂĄrio de @ferdaber aqui] (typescript-cheatsheets/react#57).

Hooks

HĂĄ suporte para Hooks em @types/react a partir da versĂŁo v16.8.

useState

InferĂȘncia automĂĄtica de tipos funciona bem com valores simples

const [val, toggle] = React.useState(false);
//  infere-se que `val` Ă© do tipo boolean
// `toggle` aceita apenas booleans

Veja tambĂ©m no artigo em inglĂȘs (utilizando Using Inferred Types se precisar usar um tipo complexo para o qual vocĂȘ depende da inferĂȘncia.

No entanto, muitos hooks sĂŁo inicializados com valores nulos e vocĂȘ pode se perguntar como deve fazer para definir o tipo. Declare explicitamente o tipo e use um tipo de uniĂŁo (union type):

const [user, setUser] = React.useState<IUser | null>(null);

// mais adiante...
setUser(newUser);

VocĂȘ tambĂ©m pode usar asserçÔes de tipo (type assertions) se um estado for inicializado logo apĂłs o setup e sempre tiver um valor definido apĂłs o setup:

const [user, setUser] = React.useState<IUser>({} as IUser);

// mais adiante...
setUser(newUser);

"Mentimos" temporariamente para o compilador de Typescript que {} Ă© do tipo IUser. VocĂȘ deve entĂŁo configurar o estado de user — se nĂŁo o fizer, o resto do seu cĂłdigo pode depender do fato de que user Ă© do tipo IUser e isso pode levar a erros em tempo de execução (runtime errors).

useReducer

VocĂȘ pode utilizar UniĂ”es de tipos com propriedades definidas (Discriminated Unions) para actions da função reducer. NĂŁo esqueça de definir o tipo de retorno, caso contĂĄrio, o compilador irĂĄ inferir o tipo.

const initialState = { count: 0 };

type ACTIONTYPE =
  | { type: "increment"; payload: number }
  | { type: "decrement"; payload: string };

function reducer(state: typeof initialState, action: ACTIONTYPE) {
  switch (action.type) {
    case "increment":
      return { count: state.count + action.payload };
    case "decrement":
      return { count: state.count - Number(action.payload) };
    default:
      throw new Error();
  }
}

function Counter() {
  const [state, dispatch] = React.useReducer(reducer, initialState);
  return (
    <>
      Count: {state.count}
      <button onClick={() => dispatch({ type: "decrement", payload: "5" })}>
        -
      </button>
      <button onClick={() => dispatch({ type: "increment", payload: 5 })}>
        +
      </button>
    </>
  );
}

Veja no TypeScript Playground

Uso do tipo `Reducer` da biblioteca `redux`

Caso vocĂȘ use a biblioteca redux para escrever a reducer function, ela fornece um helper conveniente do formato Reducer<State, Action> que cuida do tipo do retorno para vocĂȘ.

Assim, o exemplo de reducer acima se torna:

import { Reducer } from 'redux';

export function reducer: Reducer<AppState, Action>() {}

useEffect / useLayoutEffect

Ambos useEffect e useLayoutEffect são usados para executar efeitos colaterais e retornam uma função de limpeza opcional, o que significa que se eles não lidam com retorno de valores, nenhum tipo é necessårio. Ao usar useEffect, tome cuidado para não retornar nada além de uma função ou undefined, caso contrårio, tanto o TypeScript quanto o React apresentarão error. Isso pode ser sutil ao usar arrow functions:

function DelayedEffect(props: { timerMs: number }) {
  const { timerMs } = props;

  useEffect(
    () =>
      setTimeout(() => {
        /* faça coisas aqui */
      }, timerMs),
    [timerMs]
  );
  // um exemplo ruim! setTimeout implicitamente retorna nĂșmero (tipo number)
  // porque o corpo da arrow function nĂŁo estĂĄ entre chaves
  return null;
}
Solução para o exemplo acima
function DelayedEffect(props: { timerMs: number }) {
  const { timerMs } = props;

  useEffect(() => {
    setTimeout(() => {
      /* faça coisas aqui */
    }, timerMs);
  }, [timerMs]);
  // melhor; utilize a keyword void para ter certeza de que retornarĂĄ undefined
  return null;
}

useRef

Em TypeScript, useRef retorna uma referĂȘncia que pode ser somente leitura ou mutĂĄvel, a depender se o tipo fornecido cobre totalmente o valor inicial ou nĂŁo. Escolha um que se adapte ao seu caso de uso.

Opção 1: ref de um elemento da DOM

Para acessar um elemento da DOM: forneça apenas o tipo de elemento como argumento e use null como valor inicial. Neste caso, a referĂȘncia retornada terĂĄ um .current somente leitura que Ă© gerenciado pelo React. O TypeScript espera que vocĂȘ dĂȘ esta referĂȘncia Ă  prop ref de um elemento:

function Foo() {
  // - Se possĂ­vel, seja o mais especĂ­fico possĂ­vel. Por exemplo, HTMLDivElement
  // Ă© melhor que HTMLElement e muito melhor que Element.
  // - Em termos técnicos, isso retorna RefObject<HTMLDivElement>
  const divRef = useRef<HTMLDivElement>(null);

  useEffect(() => {
    // Observe que ref.current pode ser null. Isso Ă© esperado, porque vocĂȘ pode
    // renderizar condicionalmente o elemento da ref, ou vocĂȘ poderia esquecer de atribuĂ­-lo a um elemento
    if (!divRef.current) throw Error("divRef is not assigned");

    // Agora vocĂȘ tem certeza que divRef.current Ă© um HTMLDivElement
    doSomethingWith(divRef.current);
  });

  // Atribua a ref a um elemento para que o React possa gerenciar-lo pra vocĂȘ
  return <div ref={divRef}>etc</div>;
}

Se vocĂȘ tem certeza de que divRef.current nunca serĂĄ nulo, tambĂ©m Ă© possĂ­vel usar o operador de asserção nĂŁo nulo !:

const divRef = useRef<HTMLDivElement>(null!);
// Mais tarde... nĂŁo precisa checar se o elemento Ă© nulo
doSomethingWith(divRef.current);

Observe que vocĂȘ estĂĄ desativando a segurança de tipo aqui - vocĂȘ terĂĄ um erro de tempo de execução se esquecer de atribuir a referĂȘncia a um elemento na renderização ou se o elemento com ref for renderizado condicionalmente.

Dica: Escolhendo qual `HTMLElement` usar

Refs demandam especificidade - nĂŁo Ă© suficiente apenas especificar qualquer HTMLElement antigo. Se vocĂȘ nĂŁo souber o nome do tipo de elemento necessĂĄrio, verifique [lib.dom.ts](https://github.com/microsoft/TypeScript/blob/v3.9.5/lib/lib.dom. d.ts#L19224-L19343) ou cometa um erro de tipo intencional e deixe o compilador lhe dizer o tipo correto:

image

Opção 2: Valor ref mutåvel

Para ter um valor mutåvel: forneça o tipo desejado e verifique se o valor inicial pertence totalmente a esse tipo:

function Foo() {
  // Tecnicamente, isto retorna MutableRefObject<number | null>
  const intervalRef = useRef<number | null>(null);

  // VocĂȘ mesmo gerĂȘncia a ref (por isso se chama MutableRefObject!)
  useEffect(() => {
    intervalRef.current = setInterval(...);
    return () => clearInterval(intervalRef.current);
  }, []);

  // A ref (intervalRef) nĂŁo Ă© passado para a prop "ref" de nenhum elemento
  return <button onClick={/* clearInterval the ref */}>Cancel timer</button>;
}

Veja tambĂ©m (conteĂșdo em inglĂȘs)

useImperativeHandle

NĂŁo temos muito ainda sobre esse tema, hĂĄ uma discussĂŁo nas issues do repositĂłrio original. Por favor, contribua se puder!

type ListProps<ItemType> = {
  items: ItemType[];
  innerRef?: React.Ref<{ scrollToItem(item: ItemType): void }>;
};

function List<ItemType>(props: ListProps<ItemType>) {
  useImperativeHandle(props.innerRef, () => ({
    scrollToItem() {},
  }));
  return null;
}

Custom Hooks

Se vocĂȘ estiver retornando um array em seu Custom Hook (hooks customizados), vocĂȘ vai querer evitar a inferĂȘncia de tipo, pois o TypeScript irĂĄ inferir um tipo de uniĂŁo (quando, na verdade, vocĂȘ quer tipos diferentes em cada posição do array). Em vez disso, use const assertions do TypeScript 3.4:

export function useLoading() {
  const [isLoading, setState] = React.useState(false);
  const load = (aPromise: Promise<any>) => {
    setState(true);
    return aPromise.finally(() => setState(false));
  };
  return [isLoading, load] as const; // infere [boolean, typeof load] ao invés de (boolean | typeof load)[]
}

Veja no TypeScript Playground

Dessa forma, quando vocĂȘ desestrutura (desctructure), vocĂȘ obtĂ©m os tipos certos com base na posição de desestruturação.

Alternativa: definir um tipo de retorno de tupla (tuple)

Se vocĂȘ estĂĄ tendo problemas com const assertions, vocĂȘ tambĂ©m pode declarar ou definir os tipos do retorno da função:

export function useLoading() {
  const [isLoading, setState] = React.useState(false);
  const load = (aPromise: Promise<any>) => {
    setState(true);
    return aPromise.finally(() => setState(false));
  };
  return [isLoading, load] as [
    boolean,
    (aPromise: Promise<any>) => Promise<any>
  ];
}

Uma função auxiliar que define o tipe de tuplas automaticamente tambĂ©m pode ser Ăștil se vocĂȘ escrever muitos custom hooks:

function tuplify<T extends any[]>(...elements: T) {
  return elements;
}

function useArray() {
  const numberValue = useRef(3).current;
  const functionValue = useRef(() => {}).current;
  return [numberValue, functionValue]; // o tipo fica (number | (() => void))[]
}

function useTuple() {
  const numberValue = useRef(3).current;
  const functionValue = useRef(() => {}).current;
  return tuplify(numberValue, functionValue); // o tipo fica [number, () => void]
}

Saiba que a equipe do React recomenda que custom hooks que retornam mais de dois valores usem objetos em vez de tuplas.

Leituras sobre Hooks + TypeScript (em inglĂȘs):

Se vocĂȘ estiver escrevendo uma biblioteca de Hooks, nĂŁo esqueça que vocĂȘ tambĂ©m deve expor os tipos para os usuĂĄrios utilizarem.

Exemploes de bibliotecas React Hooks + TypeScript:

Tem algo a acrescentar? - link para o repositĂłrio original.