Escritura estática en una aplicación React

En 2016, TypeScript comenzó a tomar nuevas alturas. Los desarrolladores comenzaron a reescribir por completo muchas tecnologías populares y agregaron soporte para análisis estático a las plataformas existentes. Tal proceso global agregó más estabilidad a la base de código de miles, e incluso decenas de miles de proyectos.

¿Por qué reaccionar? A partir de hoy, esta biblioteca, sin duda, domina en el contexto de los competidores. Alrededor de React, se ha formado la comunidad de desarrolladores más grande del mundo. Cada tercer SPA está escrito en esta plataforma. También hay muchos grandes proyectos relacionados con el uso de React Native, una plataforma para iOS, UWP y aplicaciones de Android basadas en React.js.

Por lo tanto, hoy analizaremos las posibilidades que ofrece la integración de dos herramientas súper populares: TypeScript y React.



Ejemplos


Primero, veamos qué tipos podemos usar para React.
Comencemos de manera simple y agreguemos tipos al 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 o Componente sin estado, debemos usar una definición de tipo React.FunctionComponent. También podemos definir tipos para el argumento de accesorios: campos que el componente pasa al componente. En este caso, los accesorios solo pueden contener un campo de nombre de tipo cadena.

Todo esto no parece complicado. ¿Qué pasa con los componentes de clase?

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

En el ejemplo de la clase, creamos dos interfaces: Props y State. Con su ayuda, determinamos las firmas de los accesorios entrantes (vacíos) y la firma del estado del componente, como en el ejemplo con Componentes funcionales.

También podemos agregar valores de accesorios predeterminados.

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

Eso es todo! Nuestra pequeña aplicación React ya está fuertemente tipada a nivel de parámetros y valores de estado de componentes.

Veamos las ventajas que esto nos dio:

  • en la etapa de compilación veremos todos los desajustes de tipo;
  • un editor configurado correctamente nos ayudará a evitar errores incluso en la etapa de desarrollo simplemente resaltando las discrepancias de firmas o tipos de datos;
  • Documentación de interfaces y definiciones de tipo.


Enum en parámetros



Enum es un tipo de datos enumerados. Si agregamos este tipo a una variable o campo de interfaz, el valor de este campo o variable solo puede ser valores específicos en Enum.
Por ejemplo

  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; 

En el componente funcional que ya conocemos, queremos mostrar el color seleccionado por el usuario. En el tipo de colores de enumeración, especificamos todas las opciones de color posibles que se pueden transmitir al componente. Si el compilador de TypeScript ve un tipo no coincidente en alguna parte, se lo mostrará con un error.

Redux estricto


En 2019, todavía tenemos muchas aplicaciones ejecutándose en Redux. TypeScript puede ayudar en esta situación.

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

En este ejemplo, agregamos tipos a la aplicación a la vez en varios niveles. En primer lugar, son los reductores mismos. El reductor de entrada acepta Acción, y siempre debe devolver un objeto que coincida con el tipo HelloWorldStateProps. Dado el número de reductores que hay en una aplicación moderna, esta es una innovación muy útil. Además, cada acción que tenemos tiene una firma de acción estricta.

El siguiente nivel de escritura es componente. Aquí hemos aplicado la herencia de tipos a AppProps y AppState. ¿Por qué escribir más cuando ya tenemos tipos de datos con tales firmas? Es más fácil mantener el sistema. Si cambia algunos elementos, se producirán cambios para todos los herederos.

Conclusión


TypeScript es un lenguaje realmente útil que se ejecuta sobre JavaScript. Junto con React, proporciona prácticas de programación realmente impresionantes para aplicaciones frontend.

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


All Articles