Digitação estática em um aplicativo React

Em 2016, o TypeScript começou a assumir novos patamares. Os desenvolvedores começaram a reescrever completamente muitas tecnologias populares e adicionar suporte para análise estática nas plataformas existentes. Esse processo global adicionou mais estabilidade à base de código de milhares e até dezenas de milhares de projetos.

Por que reagir A partir de hoje, essa biblioteca sem dúvida domina o cenário dos concorrentes. Em torno do React, a maior comunidade de desenvolvedores do mundo se formou. Cada terceiro SPA é escrito nesta plataforma. Também existem muitos projetos excelentes relacionados ao uso do React Native, uma plataforma para aplicativos iOS, UWP e Android baseados no React.js.

Portanto, hoje examinaremos as possibilidades que a integração de duas ferramentas super populares oferece: TypeScript e React.



Exemplos


Primeiro, vamos ver quais tipos podemos usar para o React.
Vamos começar de forma simples e adicionar tipos ao componente funcional.

import * as React from 'react'; const HelloWorld: React.FunctionComponent<{ name: string; }> = ({ name = 'World' }) => { return <div>Hello, {props.name}</div>; }; export default HelloWorld; 

Para Componente Funcional ou Componente Sem Estado, devemos usar uma definição do tipo React.FunctionComponent. Também podemos definir tipos para o argumento props - campos que o componente passa para o componente. Nesse caso, os props podem conter apenas um campo de nome do tipo string.

Tudo isso não parece complicado. E os componentes da classe?

 import * as React from 'react'; interface State { name: string; } interface Props {} class HelloWorld extends React.Component<Props, State> { state = { name: 'World' } setName(name: string) { this.setState({ name }); } redner() { return ( <React.Fragment> <hI>Hello, {this.state.name}</hI> <input value={this.state.name} onChange={(e) => this.setName(e.target.value)} /> </React.Fragment> ); } } 

No exemplo da classe, criamos duas interfaces: Adereços e Estado. Com a ajuda deles, determinamos as assinaturas dos objetos de entrada (vazios) e a assinatura do estado do componente - como no exemplo de Componentes Funcionais.

Também podemos adicionar valores de adereços padrão.

 import * as React from 'react'; interface Props { name?: string; } export default class HelloWorld extends React.Component<Props> { static defaultProps: Props = { name: 'World' }; render () { return <hI>Hello, {this.props.name}</hI>; } } 

Isso é tudo! Nosso pequeno aplicativo React já está fortemente tipado no nível de parâmetros e valores do estado do componente.

Vejamos as vantagens que isso nos deu:

  • no estágio de compilação, veremos todas as incompatibilidades de tipo;
  • um editor configurado corretamente nos ajudará a evitar erros, mesmo no estágio de desenvolvimento, simplesmente destacando as discrepâncias de assinaturas ou tipos de dados;
  • Documentação de interfaces e definições de tipo.


Enum em parâmetros



Enum é um tipo de dados enumerado. Se adicionarmos esse tipo a um campo de variável ou interface, o valor desse campo ou variável poderá ser apenas valores específicos no Enum.
Por exemplo.

  import * as React from 'react'; enum Colors { RED, BLUE, GREEN } const ColorResult: React.FunctionComponent<{ color: Colors; }> = ({ color = Colors.Red }) => { return <div>Your color is {props.color}</div>; }; export default ColorResult; 

No componente funcional que já conhecemos, queremos mostrar a cor selecionada pelo usuário. No tipo de enum Colors, especificamos todas as opções de cores possíveis que podem ser transmitidas ao componente. Se o compilador TypeScript vir uma incompatibilidade de tipo em algum lugar, ele mostrará isso com um erro.

Redux estrito


Em 2019, ainda temos muitos aplicativos em execução no Redux. O TypeScript pode ajudar nessa situação.

 import * as React from 'react'; const initialState = { name: 'World' }; type HelloWorldStateProps = Readonly<typeof initialState>; interface Action { type: string; name?: string; } const worldNameReducer = ( state: HelloWorldStateProps = initialState, action: Action ): HelloWorldStateProps => { switch (action.type) { case "SET": return { name: action.name }; case "CLEAR": return { name: initialState.name }; default: return state; } }; const set = (name): Action => ({ type: "SET", name }); const clear = (): Action => ({ type: "CLEAR" }); const store = createStore( combineReducers({ world: worldNameReducer }) ); type StateProps = ReturnType<typeof mapStateToProps>; type DispatchProps = typeof mapDispatchToProps; interface AppProps extends StateProps, DispatchProps {} interface AppState extends StateProps {} class App extends React.Component<AppProps, AppState> { state = { name: initialState.name } setName(name: string) { this.setState({ name }); } render() { const { set, clear, name } = this.props; return ( <div> <hI>Hello, {name}</hI> <input value={this.state.name} onChange={(e) => this.setName(e.target.value)} /> <button onClick={() => set(this.state.name)}>Save Name</button> <button onClick={() => clear()}>Clear</button> </div> ); } } const mapStateToProps = ({ world }: { world: HelloWorldStateProps }) => ({ name: world.name, }); const mapDispatchToProps = { set, clear }; const AppContainer = connect( mapStateToProps, mapDispatchToProps )(App); render( <Provider store={store}> <AppContainer /> </Provider>, document.getElementById("root") ); 

Neste exemplo, adicionamos tipos ao aplicativo de uma só vez em vários níveis. Primeiro de tudo, são os próprios redutores. O redutor de entrada aceita Action e sempre deve retornar um objeto que corresponda ao tipo HelloWorldStateProps. Dado quantos redutores existem em uma aplicação moderna, essa é uma inovação muito útil. Além disso, toda ação que temos possui uma assinatura de ação estrita.

O próximo nível de digitação é componente. Aqui nós aplicamos a herança de tipo ao AppProps e AppState. Por que escrever mais quando já temos tipos de dados com essas assinaturas? É mais fácil manter o sistema. Se você alterar alguns elementos, ocorrerão alterações para todos os herdeiros.

Conclusão


TypeScript é uma linguagem realmente útil rodando sobre JavaScript. Em conjunto com o React, ele fornece práticas de programação verdadeiramente impressionantes para aplicativos Frontend.

Source: https://habr.com/ru/post/pt465461/


All Articles