40

I've got a prop on a ReactJS Component that's either null or an Immutable Map.

At the bottom of my widget if I write:

MyComponent.propTypes = {
    myMap: React.PropTypes.instanceOf(Immutable.Map)
};

I am leaving this open to the possibility of being null, undefined, or a Map.

How can I make this required and of type null or map only?

https://facebook.github.io/react/docs/typechecking-with-proptypes.html

I see this example but I do not know how to tailor the syntax to my needs or if it is even possible.

Edit: If a property is null, then it is still there but undefined means that it's not been included altogether.

For example:

<Component id={1} data={null} />
<Component id={2} data={Immutable.Map()} />
<Component id={3} />
user1261710
  • 2,539
  • 5
  • 41
  • 72
  • What's the difference you see in a property not being there or it being null? – mfirry Nov 21 '16 at 22:17
  • Possible duplicate of [How can I declare a PropType corresponding to a nullable number?](https://stackoverflow.com/questions/37842868/how-can-i-declare-a-proptype-corresponding-to-a-nullable-number) – Mosè Raguzzini Sep 19 '18 at 14:47
  • A possible solution is under discussion here https://github.com/facebook/prop-types/pull/90, adding a `isDefined()` and a `isNotNull()` – Gustavo Coelho Sep 19 '19 at 18:20

8 Answers8

22

It is possible to use PropTypes.oneOf([null]).isRequired. It should allow null, and nothing else. You can combine that with any other type:

PropTypes.oneOfType([
  PropTypes.string.isRequired,
  PropTypes.oneOf([null]).isRequired,
]).isRequired

Edit: I just had this prop type fail for me when given a null prop using prop-types 15.7.2, so I'm not sure this works anymore (if it ever did?). I reverted to allowing both undefineds and nulls by just not using isRequired.

Lars Nyström
  • 5,786
  • 3
  • 32
  • 33
14

I had similar problem and that's how I got here. I found a solution that's good enough for me, so I might as well share it.

In short, I removed .isRequired and set defaultProps to null.

I wanted something like this:

// this won't work, because `PropTypes.null` doesn't exists!
MyComponent.propTypes = {
  item: PropTypes.oneOfType([ItemPropTypesShape, PropTypes.null]).isRequired,
};

// this also won't work!
MyComponent.propTypes = {
  item: PropTypes.oneOfType([ItemPropTypesShape, PropTypes.instanceOf(null)]).isRequired,
};

The null is always treated as error when prop is required.

I ended up doing this:

MyComponent.propTypes = {
  item: ItemPropTypesShape,
};

MyComponent.defaultProps = {
  item: null,
};

If PropTypes is all we have, this works for me!

kamyl
  • 5,938
  • 4
  • 23
  • 29
11

This requirement seems to be unsupported with the current version of React.

Refer to React issue #2166 for more details. This issue discusses the possibility of an isRequiredOrNull property in addition to isRequired. Bottom line:

I wouldn't expect there to be further changes to PropTypes. Flow has become much more mature recently, and from what I heard from the React team, it is the longer term solution to type checking. This puts PropTypes into the same "compatibility" bucket in terms of priorities—like createClass or React addons, they are still supported, but only with bugfixes and performance improvements, without adding new features or changing the API.

In other words, if you require more sophisticated type checking, use Flow instead.

TimoStaudinger
  • 41,396
  • 16
  • 88
  • 94
5

Seems like PropTypes.instanceOf(null) works.

  • react@16.8
  • prop-types@15.6
wowkalucky
  • 114
  • 1
  • 2
  • 4
  • `TS2345: Argument of type 'null' is not assignable to parameter of type 'new (...args: any[]) => {}'.` – Simon Mar 03 '20 at 22:29
  • 1
    Warning: Failed prop type: Right-hand side of 'instanceof' is not an object Doesn't work on React 16.8 with prop-types 15.7 so I'm doubting this on 15.6 – Jeff Klink May 28 '20 at 18:51
3

You can use the prop type without .isRequired.

MyComponent.propTypes = {
    name: PropTypes.string
}

And define the null value in the defaultProps

MyComponent.defaultProps = {
    name: null
}
Lianel
  • 101
  • 10
Mohammadreza Khedri
  • 2,523
  • 1
  • 11
  • 22
2

Maybe too late but this work for me, is a custom propType. More info in react docs: https://reactjs.org/docs/typechecking-with-proptypes.html#proptypes

static propTypes = {
  myMap: function(props, propName, componentName) {
    if (props[propName] !== null && !(props[propName] instanceof Immutable.Map)) {
      return new Error(
        'Invalid prop `' + propName + '` supplied to `' + componentName + '`. Expected null or Immutable.Map, but received ' + typeof props[propName] + '. Validation failed.'
      )
    }
  },
}
TomasDisk
  • 21
  • 2
0

To help with this quite common issue, I created a clean and fully-typed wrapper called better-prop-types:

import BetterPropTypes from 'better-prop-types'

// ...

MyComponent.propTypes = {
  myMap: BetterPropTypes.PropTypes.instanceOf(Immutable.Map).isRequiredButNullable
}
Ivan Gabriele
  • 6,433
  • 5
  • 39
  • 60
0
PropTypes.shape({ current: PropTypes.object })
Esset
  • 916
  • 2
  • 15
  • 17
Mark
  • 1
  • 1
    Your answer could be improved with additional supporting information. Please [edit] to add further details, such as citations or documentation, so that others can confirm that your answer is correct. You can find more information on how to write good answers [in the help center](/help/how-to-answer). – Community Oct 26 '22 at 02:03
  • While this code may answer the question, providing additional context regarding how and/or why it solves the problem would improve the answer's long-term value. – nima Oct 30 '22 at 07:39