Published on

Présentation des propTypes en React.js afin de typer vos props

Pour éviter les erreurs il est possible d'appliquer des Proptypes aux composants. Cela permet de soulever une erreur si votre composant est mal hydraté, soit par manquement de variable ou par défaut de types de variables. C'est une façon de solidifier votre code et d'avoir une stabilité conséquente surtout quand votre application prend de l'ampleur et qu'il est utilisé par plusieurs développeurs qui vont utiliser vos composants sans forcément connaître l'entièreté des détails et qui peuvent parfois mal implémenter les choses.

La façon la plus courante aujourd'hui est d'implémenter les propTypes mais il existe d'autres solutions comme Flow qui est extrêmement à la mode et qui fonctionne un peu mieux que propType, Flow (https://flow.org/en/docs/react/) permet de typer plus efficacement les composants et s'approche d'une syntaxe TypeScript qui est également très solide.

Implémentation

Il faut dans un premier temps importer prop-types dans la première partie de votre code après l'avoir installé via NPM ou YARN. Une fois que cela est fait, il est possible d'implémenter les propTypes de la manière suivante :

import PropTypes from 'prop-types'

MyComponent.propTypes = {
  title: PropTypes.string.isRequired,
  heading: PropTypes.number,
}

Voici un exemple très simple qui oblige le fait d'avoir un prop title de nature string et un autre prop heading non obligatoire sous la forme d'un entier. Il existe plusieurs vérifications possibles notamment sur la nature des props, sur le fait qu'il soit facultatif ou obligatoire.

Exemples de vérification

import PropTypes from 'prop-types'

MyComponent.propTypes = {
  // You can declare that a prop is a specific JS type. By default, these
  // are all optional.
  optionalArray: PropTypes.array,
  optionalBool: PropTypes.bool,
  optionalFunc: PropTypes.func,
  optionalNumber: PropTypes.number,
  optionalObject: PropTypes.object,
  optionalString: PropTypes.string,
  optionalSymbol: PropTypes.symbol,

  // Anything that can be rendered: numbers, strings, elements or an array
  // (or fragment) containing these types.
  optionalNode: PropTypes.node,

  // A React element.
  optionalElement: PropTypes.element,

  // You can also declare that a prop is an instance of a class. This uses
  // JS's instanceof operator.
  optionalMessage: PropTypes.instanceOf(Message),

  // You can ensure that your prop is limited to specific values by treating
  // it as an enum.
  optionalEnum: PropTypes.oneOf(['News', 'Photos']),

  // An object that could be one of many types
  optionalUnion: PropTypes.oneOfType([
    PropTypes.string,
    PropTypes.number,
    PropTypes.instanceOf(Message),
  ]),

  // An array of a certain type
  optionalArrayOf: PropTypes.arrayOf(PropTypes.number),

  // An object with property values of a certain type
  optionalObjectOf: PropTypes.objectOf(PropTypes.number),

  // An object taking on a particular shape
  optionalObjectWithShape: PropTypes.shape({
    color: PropTypes.string,
    fontSize: PropTypes.number,
  }),

  // You can chain any of the above with `isRequired` to make sure a warning
  // is shown if the prop isn't provided.
  requiredFunc: PropTypes.func.isRequired,

  // A value of any data type
  requiredAny: PropTypes.any.isRequired,

  // You can also specify a custom validator. It should return an Error
  // object if the validation fails. Don't `console.warn` or throw, as this
  // won't work inside `oneOfType`.
  customProp: function (props, propName, componentName) {
    if (!/matchme/.test(props[propName])) {
      return new Error(
        'Invalid prop `' +
          propName +
          '` supplied to' +
          ' `' +
          componentName +
          '`. Validation failed.'
      )
    }
  },

  // You can also supply a custom validator to `arrayOf` and `objectOf`.
  // It should return an Error object if the validation fails. The validator
  // will be called for each key in the array or object. The first two
  // arguments of the validator are the array or object itself, and the
  // current item's key.
  customArrayProp: PropTypes.arrayOf(function (
    propValue,
    key,
    componentName,
    location,
    propFullName
  ) {
    if (!/matchme/.test(propValue[key])) {
      return new Error(
        'Invalid prop `' +
          propFullName +
          '` supplied to' +
          ' `' +
          componentName +
          '`. Validation failed.'
      )
    }
  }),
}

Vous retrouverez cet exemple ainsi que des explications plus avancés sur le sujet sur https://reactjs.org/docs/typechecking-with-proptypes.html

Valeurs par défaut

Il est possible de vérifier des types de props et de soulever une erreur dans la console, mais il est également possible de mettre en place des valeurs par défaut pour vos composants. C'est aussi simple que pour la vérification, mais à la place de déclarer votre objet comme propTypes, il suffit de le déclarer comme defaultProps, voici un exemple avec notre composant précédent :

import PropTypes from 'prop-types'

MyComponent.propTypes = {
  title: PropTypes.string.isRequired,
  heading: PropTypes.number,
}

MyComponent.defaultProps = {
  heading: 1,
}

Dans le cas où le prop est obligatoire, il n'est pas impératif d'avoir une valeur par défaut puisqu'elle va être forcément renseignée; c'est le cas où votre cette valeur est facultative où la notion de prop par défaut est intéressante.