typescript-cheatsheets / react-pt

React Typescript Cheatsheet in Portuguese ūüáßūüá∑

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

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.

About

React Typescript Cheatsheet in Portuguese ūüáßūüá∑

License:MIT License