eddy
eddy

Reputation: 4413

Is it possible to use PropTypes to validate Dictionary-like objects?

I need to validate dictionary-like objects in my reducers, but since I'm already using Babel I don't want to resort to tools like Typescript.

Take this object as an example:

posts : {
    byId : {
        "post1" : {
            id : "post1",
            author : "user1",
            body : "......",
            comments : ["comment1", "comment2"]    
        },
        "post2" : {
            id : "post2",
            author : "user2",
            body : "......",
            comments : ["comment3", "comment4", "comment5"]    
        }
    }
    allIds : ["post1", "post2"]
}

How could I express my expectations for the byId object using PropTypes? Is it possible? If so, how?

Upvotes: 6

Views: 3301

Answers (2)

Andrew Li
Andrew Li

Reputation: 57964

You can write custom proptype checkers if you can't achieve what you wan't with PropTypes' builtin proptypes.

If you want an all the values of the byId to be objects with the properties id, author, body and comments, you can use shape, objectOf, and arrayOf. If you want allIds to include all the keys of byId you can write a custom validator:

posts: PropTypes.shape({
  byId: PropTypes.objectOf(PropTypes.shape({
    id: PropTypes.string,
    author: PropTypes.string,
    body: PropTypes.string,
    comments: PropTypes.arrayOf(PropTypes.string)
  })),
  allIds(props, propName, componentName) {
    if(!Object.keys(props.byId).every(postID => props[propName].includes(postID))) {
      return new Error('allIds must include all the ids provided to byId!');
    }
  }
})

The above uses shape so it expects a posts object with the keys byId and allIds. It expects byId to be an object with the property values to also be object of a shape, with id, author and body being strings, with comments being an array of strings. Finally, it uses a custom proptype validator that checks if every key in byId (the post IDs) exists in allIds. If not, then throw an error. Beware though, this won't cover the case that allIds has post IDs that don't exist in byIds. See How to know if two arrays have the same values for more solutions. You can add isRequired where necessary.

Upvotes: 10

cfraser
cfraser

Reputation: 961

Using PropTypes.shape()

posts: PropTypes.shape({
    byId: PropTypes.sth() // could be shape() or sth else
}),

Upvotes: -2

Related Questions