Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to use PropTypes.shape with Typescript

I'm refactoring a React application from Javascript to Typescript but I'm having some troubles migrating especially the shape PropType. My code looks like this right now:

import React from 'react';
import PropTypes from 'prop-types';

interface FooterProps {
  labels: FooterLabels;
}

interface FooterLabels {
  body: string;
}

const Footer: React.FC<FooterProps> = ({ labels }) => (
  <div className="footer">
    {/* ... */}
  </div>
);

Footer.propTypes = {
  labels: PropTypes.shape({
    body: PropTypes.string.isRequired
  }).isRequired
};

export default Footer;

But I'm getting an error in the PropTypes:

Type 'Validator<InferProps<{ body: Validator<string>; }>>' is not assignable to type 'Validator<FooterLabels>'.
  Type 'InferProps<{ body: Validator<string>; }>' is not assignable to type 'FooterLabels'.
    Property 'body' is optional in type 'InferProps<{ body: Validator<string>; }>' but required in type 'FooterLabels'.ts(2322)
FooterAppPromo.tsx(5, 3): The expected type comes from property 'labels' which is declared here on type 'WeakValidationMap<FooterProps>'

I'm new to Typescript so sometimes I don't really know what I'm doing, but I tried to do stuff like:

Footer.propTypes = {
  labels: PropTypes.shape<FooterLabels>({
    body: PropTypes.string.isRequired
  }).isRequired
};

But I'm getting the errors. I tried searching for example implementations but I couldn't find any.

EDIT

Typescript types and PropTypes are not the same thing. You can easily write an example where a Typescript validation passes but you still get a PropTypes warning (e.g. an external API that returns a number where should be a string). Here's two articles explaining why:

  • PropTypes in a TypeScript React Application
  • https://fettblog.eu/typescript-react/prop-types/

So my question is how can I make nested PropTypes objects (PropTypes.shape() or maybe PropTypes.objectOf()) work with TypeScript?

like image 843
Thiago Loddi Avatar asked Dec 11 '19 16:12

Thiago Loddi


2 Answers

The PropTypes error is because you are trying to use a PropType.shape, the shape allows you to have optional values on your shape, and in this case, your interface is strict, which means you do not have any kind of optional value, and React.Validator is trying to infer your types behind with your interfaces and that makes the error appear.

In simple words, if you have a strict interface with non-optional values, instead of using PropType.shape you should use PropType.exact and that should prevent the error.

E.G:

Footer.propTypes = {
  labels: PropTypes.exact({
    body: PropTypes.string
  }).isRequired
};

For that reason on your error message appears

Property 'body' is optional in type 'InferProps<{ body: Validator; }>' but required in type 'FooterLabels'.ts(2322)

EDITED

This happens only because you are using on the component const Footer: React.FC<FooterProps> = ({ labels }) => (

The FC ( FunctionComponent Interface ) looking into the interfaces is presented as

interface FunctionComponent<P = {}> {
        (props: PropsWithChildren<P>, context?: any): ReactElement<any, any> | null;
        propTypes?: WeakValidationMap<P>;
        contextTypes?: ValidationMap<any>;
        defaultProps?: Partial<P>;
        displayName?: string;
    }

The line that we should highlight here is the propTypes?: WeakValidationMap<P>; This is the one that infers our types based on our PropTypes.

You have a second option to use types on React, but I do not recommend it, instead of using FC, you can use ReactNode type, but you will lose the inferences that you have on the FC interface type inferring.

E.G. function Footer = ({ labels }:FooterProps): ReactNode => (

like image 140
Nicolás Juárez Nuño Avatar answered Nov 02 '22 09:11

Nicolás Juárez Nuño


Actually you don't need propTypes here - labels got just one nested field body that is typeof FooterLabels.

interface FooterProps {
  labels: {
     body: FooterLabels;
  };
}
like image 44
kind user Avatar answered Nov 02 '22 09:11

kind user