Search code examples
reactjstypescriptreact-proptypes

Proptypes: Verify an array of interface as props in react


I have some troubles on a react component and I would need some help for a solution...

I want to use propTypes on my component in order to have a runtime verification. I have implemented interfaces for the props I want to use. Some of the props are arrays of interfaces. Here is what I have so far:

Definition of types:

   export type Point = {
    /** x value */
    readonly x: number;

    /** y value */
    readonly y: number;
  }

  /** Contains information relative to a line plot */
  export interface LineData {
    /** name of the line. Will be used in legend */
    readonly legend: string;

    /** Color of the line. If unspecified, a color will be chosen automatically */
    color?: string;

    /** width of the line in pixel. If not specified, a default value is provided */
    strokeWidth?: number;

    /** Contains all points associated with this line */
    readonly data: Array<Point>;
  }

  /** Graph properties */
  export interface GraphProps {
    /** An array that contains all line definitions */
    readonly lineDatas: Array<LineData>;

    /** The plot's title. Is set in upper left corner of the plot, outside border */
    readonly plotTitle?: string;

    /** Plot title's font size */
    readonly plotTitleFontSize?: number;
  }

Implementation of Proptypes:

Graph.propTypes = {  
  lineDatas: PropTypes.arrayOf(PropTypes.shape({
    legend : PropTypes.string.isRequired,
    color:PropTypes.string,
    strokeWidth: PropTypes.number,
    data: PropTypes.arrayOf(PropTypes.shape({
      x: PropTypes.number,
      y: PropTypes.number
    }))
  })),
  plotTitle: PropTypes.string,
  plotTitleFontSize: PropTypes.number,
};

I get this error, even though egend is set as required...

Property 'legend' is optional in type 'InferProps<{ legend: Requireable<string>; color: Requireable<string>; strokeWidth: Requireable<number>; data: Requireable<InferProps<{ x: Requireable<number>; y: Requireable<...>; }>[]>; }>' but required in type 'LineData'.

Thanks for the help!


Solution

  • Posting my comments as an answer.

    You should use PropTypes.exact() instead of PropTypes.shape() and also add some missing .isRequired calls to lineData and data fields.

    The prototypes code would be:

    Graph.propTypes = {  
      lineDatas: PropTypes.arrayOf(PropTypes.exact({
        legend : PropTypes.string.isRequired,
        color:PropTypes.string,
        strokeWidth: PropTypes.number,
        data: PropTypes.arrayOf(PropTypes.exact({
          x: PropTypes.number,
          y: PropTypes.number
        })).isRequired
      })).isRequired,
      plotTitle: PropTypes.string,
      plotTitleFontSize: PropTypes.number,
    };