Démarrer sur React Native avec Expo, TypeScript et ESLint

Présentation

Tout d'abord avant de commençer nous allons faire un petit rappel de ce que sont React Native, Expo et TypeScript.

React Native : C'est un framework pour créer des applications natives en utilisant React. React Native permet de construire des applications mobiles en utilisant seulement JavaScript.

Expo : C'est un ensemble d'outils gratuit et open source développé autour de React Native qui permet de gagner du temps dans le développement d'applicaton iOS et Android.

TypeScript : C’est un langage open-source édité par Microsoft qui permet d’avoir un sur-ensemble à javascript offrant des fonctionnalités complémentaires comme par exemple le typage statique et générique, les classes abstraites ou bien les énumérations.

Installation de Expo et création d'un nouveau projet

Avant de pouvoir installer Expo nous avons besoin de Node que vous pouvez installer en cliquant ici.

Ensuite nous avons besoin de expo-cli cela nous permettra par la suite de créer notre projet.

npm install expo-cli --global

Avant de créer le projet je vous recommande de vous connecter à votre compte expo ou bien d'en créer un avant de passer à la suite.

expo register # créer un compte
expo login  # se connecter

Maintenant nous allons pouvoir créer notre projet :

expo init first-expo-project

Une fois la commande exécutée il vous sera demandé quel type de template vous souhaitez utiliser :

blank : Un template vide avec juste les dépendances nécéssaires pour lancer votre application.

tab : Un template intégrant React Navigation avec des tabs et des exemples d'écrans.

Pour notre exemple choisissez le template blank

Choisir le template

Ensuite si vous utilisez yarn il vous sera proposé de l'utiliser pour installer les dépendances. Faite votre choix en fonction de vos préférences.

Utiliser yarn ?

Une fois le projet créé placez vous dans le dossier de ce dernier et lancez l'application :

cd first-expo-project
expo start

Une fois votre application lancée vous devriez voir quelque chose de similaire à ça :

Lancer l'application expo

A ce moment vous avez plusieurs possibilités pour lancer votre application.

La première : directement sur votre mobile pour ce faire vous devez installer le client expo dessus :

Une fois le client installé connectez vous avec votre compte expo et scannez le QR Code directement depuis le client Expo pour Android et pour iOS soit avec l'application caméra (iOS 11 ou +) soit avec une application pour lire les QRCodes.

Alternative :

  1. Logiquement si vous êtes connecté à votre compte sur votre ordinateur, lorsque vous ouvrez le client expo votre application devrait être listée.
  2. Vous pouvez aussi envoyer un lien pour ouvrir l'application par sms depuis votre terminal en appuyant sur e.
  3. La dernière alternative consiste à installer un simulateur android ou ios et ensuite lancer votre application avec les commandes expo start --android ou expo start --ios.

Configuration

Maintenant que notre application est créée et se lance correctement nous allons pouvoir la configurer pour utiliser TypeScript et ESLint.

Configuration de TypeScript

La première chose à faire est d'ajouter TypeScript à notre projet :

yarn add typescript --dev

Ensuite nous allons ajouter les définitions des types Typescript pour Expo,React et React Native :

yarn add @types/expo @types/react @types/react-dom @types/react-native --dev

Puis nous allons ajouter un fichier tsconfig.json pour la configuration de TypeScript :

{
  "compilerOptions": {
    /* Basic Options */
    "target": "es2017" /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017','ES2018' or 'ESNEXT'. */,
    "lib": ["es6"],
    "jsx": "react-native" /* Specify JSX code generation: 'preserve', 'react-native', or 'react'. */,
    "noEmit": true /* Do not emit outputs. */,

    /* Strict Type-Checking Options */
    "strict": true /* Enable all strict type-checking options. */,
    "noImplicitAny": true /* Raise error on expressions and declarations with an implied 'any' type. */,
    "strictNullChecks": true /* Enable strict null checks. */,
    "strictFunctionTypes": true /* Enable strict checking of function types. */,
    "strictPropertyInitialization": true /* Enable strict checking of property initialization in classes. */,
    "noImplicitThis": true /* Raise error on 'this' expressions with an implied 'any' type. */,
    "alwaysStrict": true /* Parse in strict mode and emit "use strict" for each source file. */,

    /* Additional Checks */
    "noUnusedLocals": true /* Report errors on unused locals. */,
    "noUnusedParameters": true /* Report errors on unused parameters. */,
    "noImplicitReturns": true /* Report error when not all code paths in function return a value. */,
    "noFallthroughCasesInSwitch": true /* Report errors for fallthrough cases in switch statement. */,
    "forceConsistentCasingInFileNames": true,

    /* Module Resolution Options */
    "moduleResolution": "node" /* A series of entries which re-map imports to lookup locations relative to the 'baseUrl'. */ /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */,
    "allowSyntheticDefaultImports": true /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */,
    "types": ["react", "react-native"]
  },
  "include": ["App.tsx", "src"]
}

Enfin pour terminer nous allons renommer le fichier App.js en App.tsx, ajouter un dossier src qui contiendra le code de notre application et enfin ajouter un composant de test.

mv App.js App.tsx
mkdir src && cd src
mkdir components && cd components
touch HelloText.tsx

Dans le fichier HelloTest.tsx ajoutez le code suivant :

import React from 'react'
import { Text } from 'react-native'

interface Props {
  text: string;
  color: string;
}

export default ({ text, color }: Props) => <Text style={{ color }}>{text}</Text>

Puis modifiez le fichier App.tsx comme ci-dessous :

import React from 'react'
import { StyleSheet, View } from 'react-native'
import HelloText from './src/components/HelloText'

export default class App extends React.Component {
  render() {
    return (
      <View style={styles.container}>
        <HelloText
          text="Open up App.js to start working on your app!"
          color="#000"
        />
      </View>
    )
  }
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: '#fff',
    alignItems: 'center',
    justifyContent: 'center',
  },
})

Pour comprendre l'intéret de TypeScript, supprimez la propriété color du composant HelloText, vous devriez voir apparaître une erreur comme ci-dessous :

Erreur TypeScript

Ici TypeScript nous rappelle que nous avons déclaré et rendu la propriété color de notre composant HelloText obligatoire grâce à l'interface Props :

interface Props {
  text: string;
  color: string;
}
export default ({ text, color }: Props) => (
  ...

Mais puisque que nous l'ajoutons pas au composant TypeScript nous indique une erreur.

Configuration ESLint et Prettier

Pour terminer cet article nous allons ajouter ESLint et Prettier. ESLint est un linter qui va nous permettre entre autres de définir des règles pour le code de l'application et ensuite nous afficher des erreurs lorsque ces règles ne sont pas respectées.

Prettier quand à lui est un formatteur de code c'est lui qui lorsque certaines règles ne sont pas respectées va formatter le code pour qu'il respecte les règles.

Pour les différentes règles ESLint nous allons utilisé le package eslint-config-airbnb qui permet d'avoir un certain nombre de règles déjà créées ce qui va nous faire gagner du temps. Si vous le souhaitez vous pouvez définir intégralement l'ensemble de vos règles et ne pas installer ce package.

Commençons par installer ESLint, Prettier et les packages nécéssaires pour faire fonctionner le tout avec TypeScript :

yarn add eslint @typescript-eslint/eslint-plugin @typescript-eslint/parser prettier eslint-plugin-prettier eslint-config-prettier --dev

Ensuite nous allons ajoutez le package eslint-config-airbnb ainsi que les autres packages dont il a besoin pour fonctionner et nous ajoutons aussi le package eslint-plugin-react-native qui amène des règles pour react native.

yarn add eslint-config-airbnb eslint-plugin-import eslint-plugin-jsx-a11y eslint-plugin-react eslint-plugin-react-native --dev

Maintenant que tous les packages nécéssaires sont installés nous pouvons ajouter notre fichier de configuration pour ESLint. A la racine du projet ajoutez un fichier .eslintrc.js avec le contenu suivant :

module.exports = {
  parser: '@typescript-eslint/parser', // Specifies the ESLint parser
  plugins: ['@typescript-eslint', 'react-native', 'prettier'],
  parserOptions: {
    sourceType: 'module',
  },
  extends: [
    'airbnb',
    'plugin:@typescript-eslint/recommended',
    'prettier/@typescript-eslint', // Uses eslint-config-prettier to disable ESLint rules from @typescript-eslint/eslint-plugin that would conflict with prettier
    'plugin:prettier/recommended', // Enables eslint-plugin-prettier and displays prettier errors as ESLint errors.
    'prettier/react',
    'prettier/@typescript-eslint',
  ],
  settings: {
    'import/resolver': {
      node: {
        extensions: ['.ts', '.tsx'],
      },
    },
  },
  rules: {
    'no-use-before-define': ['error', { variables: false }],
    'no-unused-vars': 2,
    '@typescript-eslint/no-unused-vars': 2,
    '@typescript-eslint/no-use-before-define': ['error', { variables: false }],
    '@typescript-eslint/explicit-member-accessibility': 'off',
    'react/jsx-filename-extension': ['error', { extensions: ['.tsx'] }],
    'react-native/no-unused-styles': 2,
    'react-native/split-platform-components': 2,
    'react-native/no-inline-styles': 0,
    'react-native/no-color-literals': 2,
    'react-native/no-raw-text': 0,
    'prettier/prettier': 2,
  },
}

Ensuite nous ajoutons le fichier de configuration de Prettier .prettierrc.js toujours à la racine :

module.exports = {
  semi: true,
  trailingComma: 'none',
  singleQuote: false,
  printWidth: 80,
  tabWidth: 2,
}

Avant de pouvoir vérifier que ESLint et Prettier fonctionne correctement nous devons ajouter deux commandes à la suite de celles existantes dans le fichier package.json

scripts:{
  ...
  "lint": "eslint src/**/*.tsx App.tsx",
  "fix": "eslint src/**/*.tsx App.tsx --fix"
}

La commande lint va lancer ESLint et nous retourner les erreurs présentes ainsi que nous indiquer celles qui sont corrigable automatiquement avec la commande fix pour les autres il faudra venir les modifiées à la main.

Afin de vérifier que ESLint fonctionne correctement lancez la commande yarn lint ou npm run lint et vous devriez vous un certain nombre d'erreurs apparaître. Corrigez en une partie avec la commande yarn fix ou npm run fix. Une fois la commande fix exécutée elle vous retournera les erreurs restantes qui devront être corrigées à la main.

Enfin si vous utilisez VSCode (cela fonctionne avec les autres ide mais je ne les utilise pas donc je connais pas leurs configurations) vous pouvez installer les extensions Prettier et ESLint puis ajouter cette configuration dans le fichier settings.json de VSCode pour que la correction et le formatage des erreurs soit automatique lorsque vous enregistrez vos fichiers.

"eslint.autoFixOnSave": true,
"eslint.validate": [
  {
    "language": "javascript",
    "autoFix": true
  },
  {
    "language": "javascriptreact",
    "autoFix": true
  },
  {
    "language": "typescript",
    "autoFix": true
  },
  {
    "language": "typescriptreact",
    "autoFix": true
  }
],
"editor.formatOnSave": true,
"[javascript]": {
  "editor.formatOnSave": false
},
"[javascriptreact]": {
  "editor.formatOnSave": false
},
"[typescript]": {
  "editor.formatOnSave": false
},
"[typescriptreact]": {
  "editor.formatOnSave": false
},

Voilà nous en avons terminé avec la configuration d'un nouveau projet React Native avec Expo, TypeScript et ESLint.

Partagez cet article si vous le souhaitez et si vous avez des questions vous pouvez me contacter par le chat.