Skip to content
This repository has been archived by the owner on Sep 1, 2024. It is now read-only.

PropTypes.exact for all props has errors #263

Open
jaydenseric opened this issue Mar 1, 2019 · 13 comments
Open

PropTypes.exact for all props has errors #263

jaydenseric opened this issue Mar 1, 2019 · 13 comments
Labels

Comments

@jaydenseric
Copy link
Contributor

Using PropTypes.exact for all the props causes errors.

Something like this:

Foo.propTypes = PropTypes.exact({
  bar: PropTypes.number.isRequired
})

Errors strangely like this:

Warning: Failed prop type: The prop `isRequired` is marked as required in `Foo`, but its value is `undefined`.
@ljharb ljharb added the bug label Mar 1, 2019
@ljharb
Copy link
Contributor

ljharb commented Mar 1, 2019

cc @asbjornh could this be related to #234?

Either way I’ll be able to look into it and have a fix out (or a passing test) this weekend.

@asbjornh
Copy link

asbjornh commented Mar 1, 2019

@ljharb You almost gave me a heart attack there (until I saw that my changes hadn't been published to npm yet) 😄

Is that a valid propTypes declaration though? Can the top-level propTypes be a validator function instead of an object literal?

@ljharb
Copy link
Contributor

ljharb commented Mar 3, 2019

@asbjornh no, but PropTypes.exact doesn't return a function, it returns an object.

@ljharb
Copy link
Contributor

ljharb commented Mar 3, 2019

@jaydenseric can you provide the exact component code for Foo here?

@asbjornh
Copy link

asbjornh commented Mar 3, 2019

@ljharb Are you sure about that? Both the following output function for me:

console.log(typeof PropTypes.exact);
console.log(typeof PropTypes.exact({ foo: PropTypes.number }));

I can reproduce @jaydenseric's case like this (it outputs the same error message):

PropTypes.checkPropTypes(
  PropTypes.exact({ bar: PropTypes.number.isRequired }),
  { bar: 1 },
  "prop",
  "Foo"
);

I can't see that Component.propTypes = PropTypes.exact({ ... }); is a documented valid use case. It would be a nice feature though!

@asbjornh
Copy link

asbjornh commented Mar 3, 2019

Oh, actually, you only need this in order to reproduce:

PropTypes.checkPropTypes(PropTypes.exact(), {}, "prop", "Foo");

I'm guessing it's because the returned function has an isRequired property (I now understand what you meant about the return value being an object), which means that the proptypes declaration declares a single prop: isRequired of type object. The following case raises no warnings:

PropTypes.checkPropTypes(PropTypes.exact(), { isRequired: {} }, "prop", "Foo");

@ljharb
Copy link
Contributor

ljharb commented Mar 3, 2019

There’s no docs in the readme, so it’s possible this implementation of exact is just a form of “shape” - as opposed to https://npmjs.com/prop-types-exact which works as you expect.

@Zaynex
Copy link

Zaynex commented May 14, 2019

because PropTypes.exact({}) is checkType function and it bind the isRequired in checkType

chainedCheckType.isRequired = checkType.bind(null, true);

and the checkPropTypes think PropTypes.exact({realProps}) is a propTypes and check itself. But the PropTypes.exact() is not we actually want to check, it should check realProps.

@Zyclotrop-j
Copy link

Zyclotrop-j commented Sep 22, 2019

I ran into this as well and so had a look at it and I guess making isRequired non-enumerable would help - the for-in loop in checkPropTypes will ignore it then:
Replace
chainedCheckType.isRequired = checkType.bind(null, true);
with

Object.defineProperty(chainedCheckType, 'isRequired ', {
  value: checkType.bind(null, true),
  enumerable: false
});

I am not sure if that breaks other things though.

@ljharb
Copy link
Contributor

ljharb commented Sep 24, 2019

Seems like perhaps isRequired should be explicitly ignored in that loop?

@mqklin
Copy link

mqklin commented Dec 6, 2020

Any updates? This makes exact useless

@asbjornh
Copy link

The error that OP describes is not unique to PropTypes.exact. It happens whenever you assign any validator as the outermost value of Component.propTypes. All of the following will result in OP's error:

Component.propTypes = PropTypes.string; // Error
Component.propTypes = PropTypes.array; // Error
Component.propTypes = PropTypes.object; // Error
Component.propTypes = PropTypes.exact({}); // Error

The documentation doesn't state this directly, but I think prop-types doesn't support using validators as the outermost value of Component.propTypes. Maybe @ljharb can confirm or deny. This limitation does make sense since React props are always objects.

Assuming that this isn't supported, what you're seeing is undefined behavior caused by incorrect use of the API.

As far as I can tell, the "bug" here is that incorrect use fo the API results in a cryptic error message which should be improved.

I guess using PropTypes.exact like in OP's example could be supported in theory, but that could require special treatment of PropTypes.exact and even changes to React. I have a hunch that the maintainers might be reluctant to do that (I know I would be).

@ljharb
Copy link
Contributor

ljharb commented Jan 15, 2021

The entire point of PropTypes.exact is to use it as the .propTypes value, so that the entire props object is checked for extra props.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Projects
None yet
Development

No branches or pull requests

6 participants