Saisie statique dans une application React

En 2016, TypeScript a commencé à prendre de nouveaux sommets. Les développeurs ont commencé à réécrire complètement de nombreuses technologies populaires et à ajouter une prise en charge de l'analyse statique aux plates-formes existantes. Un tel processus global a ajouté plus de stabilité à la base de code de milliers, voire de dizaines de milliers de projets.

Pourquoi réagir À ce jour, cette bibliothèque domine sans aucun doute dans le contexte des concurrents. Autour de React, la plus grande communauté de développeurs au monde s'est formée. Chaque troisième SPA est écrit sur cette plateforme. Il existe également de nombreux grands projets liés à l'utilisation de React Native, une plate-forme pour les applications iOS, UWP et Android basée sur React.js.

Par conséquent, aujourd'hui, nous examinerons les possibilités offertes par l'intégration de deux outils super populaires: TypeScript et React.



Des exemples


Voyons d'abord quels types nous pouvons utiliser pour React.
Commençons simples et ajoutons des types au composant fonctionnel.

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

Pour le composant fonctionnel ou le composant sans état, nous devons utiliser une définition de type React.FunctionComponent. Nous pouvons également définir des types pour l'argument props - les champs que le composant transmet au composant. Dans ce cas, les accessoires ne peuvent contenir qu'un champ de nom de type chaîne.

Tout cela ne semble pas compliqué. Qu'en est-il des composants de 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> ); } } 

Dans l'exemple de classe, nous avons créé deux interfaces: Props et State. Avec leur aide, nous avons déterminé les signatures des accessoires entrants (vides) et la signature de l'état du composant - comme dans l'exemple avec les composants fonctionnels.

Nous pouvons également ajouter des valeurs d'accessoires par défaut.

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

C'est tout! Notre petite application React est déjà fortement typée au niveau des paramètres et des valeurs d'état des composants.

Voyons les avantages que cela nous a apporté:

  • au stade de la compilation, nous verrons toutes les asymétries de types;
  • un éditeur correctement configuré nous aidera à éviter les erreurs même au stade du développement en mettant simplement en évidence les écarts de signatures ou de types de données;
  • Documentation à partir des interfaces et des définitions de types.


Énumérer les paramètres



Enum est un type de données énuméré. Si nous ajoutons ce type à une variable ou à un champ d'interface, la valeur de ce champ ou de cette variable ne peut être que des valeurs spécifiques dans Enum.
Par exemple.

  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; 

Dans le composant fonctionnel que nous connaissons déjà, nous voulons montrer la couleur sélectionnée par l'utilisateur. Dans le type Couleurs enum, nous avons spécifié toutes les options de couleurs possibles qui peuvent être transmises au composant. Si le compilateur TypeScript voit une incompatibilité de type quelque part, il vous le montrera avec une erreur.

Strict Redux


En 2019, nous avons encore de nombreuses applications en cours d'exécution sur Redux. TypeScript peut vous aider dans cette situation.

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

Dans cet exemple, nous ajoutons des types à l'application simultanément à plusieurs niveaux. Ce sont d'abord les réducteurs eux-mêmes. Le réducteur d'entrée accepte Action, et il doit toujours renvoyer un objet qui correspond au type HelloWorldStateProps. Étant donné le nombre de réducteurs dans une application moderne, il s'agit d'une innovation très utile. De plus, chaque action que nous avons a une signature d'action stricte.

Le prochain niveau de frappe est le composant. Ici, nous avons appliqué l'héritage de types à AppProps et AppState. Pourquoi écrire plus alors que nous avons déjà des types de données avec de telles signatures? Il est plus facile d’entretenir le système. Si vous modifiez certains éléments, des modifications se produiront pour tous les héritiers.

Conclusion


TypeScript est un langage vraiment utile fonctionnant au-dessus de JavaScript. Associé à React, il fournit des pratiques de programmation vraiment impressionnantes pour les applications frontales.

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


All Articles