3

I'm working with TypeScript on React, plus I'm validating props on runtime with PropTypes. Recently I updated to TypeScript 3.9.3 and since then things are breaking. Given this interface:

interface StoryQuestionsProps extends WithMediaProps {
  questionObject: {
    question: string,
    answer: string,
    nid?: string,
    path?: string,
    type?: string,
  },
  children?: JSX.Element | string,
}

If I declare these PropTypes:

StoryQuestions.propTypes = {
  questionObject: PropTypes.shape({
    question: PropTypes.string.isRequired,
    answer: PropTypes.string.isRequired,
    nid: PropTypes.string,
    path: PropTypes.string,
    type: PropTypes.string,
  }).isRequired,
  children: PropTypes.oneOfType([
    PropTypes.element,
    PropTypes.string,
  ]),
}

Throws error TS2322:

Type 'Validator; answer: Validator; nid: Requireable; path: Requireable; type: Requireable; }>>' is not assignable to type 'Validator<{ question: string; answer: string; nid?: string | undefined; path?: string | undefined; type?: string | undefined; }>'.   Type 'InferProps<{ question: Validator; answer: Validator; nid: Requireable; path: Requireable; type: Requireable; }>' is not assignable to type '{ question: string; answer: string; nid?: string | undefined; path?: string | undefined; type?: string | undefined; }'.     Types of property 'nid' are incompatible.       Type 'string | null | undefined' is not assignable to type 'string | undefined'.         Type 'null' is not assignable to type 'string | undefined'.

Instead, expecting any type:

StoryQuestions.propTypes = {
  questionObject: PropTypes.any.isRequired,
  children: PropTypes.oneOfType([
    PropTypes.element,
    PropTypes.string,
  ]),
}

it doesn't return errors, but this way I would miss the questionObject properties validation. Why propType.shape() is not working? I've also tried wrapping propTypes.shape() with propTypes.objectOf(PropTypes.shape( ... )) but has no effect.

ifthenelse
  • 647
  • 1
  • 11
  • 21
  • 1
    Unfortunately no, the Typescript code is a component library which is imported in plain javascript files. By my previous reads, PropTypes are still necessary and removing them may be not be a good a idea: https://stackoverflow.com/a/43187969 – ifthenelse May 31 '20 at 07:26
  • 1
    I ran into the same issue with a nullable boolean prop inside `PropTypes.shape()` and was able to resolve it with `PropTypes.oneOf([true, false, undefined]).isRequired` instead of `PropTypes.bool`. I'm not sure if you can adapt that to a string but I discovered this question while searching for my issue. Strings worked fine for me in TS, mine look exactly as you have your laid out – Brendan Sep 23 '20 at 17:14

1 Answers1

-1

While propTypes are an excellent tool, there is no need to use propTypes when you are working with TypeScript and React. You can simply replace the propTypes with interfaces or type aliases for your component's props.

Once you have defined the interfaces, you can safely remove the propTypes from your components. You may want to do it incrementally and test it out properly in case you break anything.

That being said, I do not see any issues with the way StoryQuestionsProps is defined.

wentjun
  • 40,384
  • 10
  • 95
  • 107
  • It’s a legacy project, and removing PropTypes while would make sense for the reasons you said, is not a viable solution. – ifthenelse May 31 '20 at 07:08
  • 3
    Actually `propTypes` provides runtime validation for the props to catch any differences between compile-time and runtime types, see https://stackoverflow.com/a/54690878/323177 for more details – Woodz May 10 '21 at 04:37
  • > there is no need to use propTypes when you are working with TypeScript and React That's not strictly true if you're building a library. Consumers may not be using TS, but you still want to provide type validation – Adam M Thompson Nov 14 '22 at 20:55
  • 1
    An example situation where this is still required would be if you're api sent a string instead of a number. Typescript wont catch this but the proptypes check will. – sam Jan 03 '23 at 11:29