In-depth object prop validation in Vue.js

Vue.js offers a simple yet effective prop validation API:

export default {
props: {
config: {
type: Object,
required: true
}
}
};

For any given prop, you can specify the expected type, and whether the prop is required or has a default value. Doing so is actually best practice, just like defining data as a function in your components.

Regarding Object props, however, there is no built-in mechanism allowing one to validate the object's keys or structure; the closest thing we have is the ability to pass in a custom validation function, so let's build upon that!

The most simple implementation could be along the lines of the following:

const configKeys = ["some", "keys", "to", "check"];

export default {
props: {
config: {
type: Object,
required: true,
validator: config => configKeys.every(key => key in config)
}
}
};

That pretty much does it! A more thorough version could support deep key checking with a dotted notation, using this package for example.

But let's go further! If you find yourself using this pattern on a regular basis, why would you not write a mixin - actually, a mixin factory - to make it easier?

/**
* @param {String} propName
* @param {String[]} keys
*
* @return {Object}
*/
function getObjectPropMixin(propName, keys) {
return {
[propName]: {
type: Object,
required: true,
validator: value => keys.every(key => key in value)
}
};
}

export default {
mixins: [getObjectPropMixin("config", ["some", "keys", "to", "check"])]
};

You could even use it multiple times in the same component if you have more than one Object prop to check; or better yet:

/**
* @param {Object} propDefs
*
* @return {Object}
*/
function getObjectPropsMixin(propDefs) {
return Object.keys(propDefs).reduce((props, key) => {
return {
...props,
[key]: {
type: Object,
required: true,
validator: value => propDefs[key].every(propKey => propKey in value)
}
}
}, {});
}

export default {
mixins: [getObjectPropsMixin({
config: ["some", "keys", "to", "check"],
anotherObject: ["and", "here", "are", "more", "dummy", "values"]
})]
};

Using such stuff gives us the confidence to reference keys in Object props directly, without defensively checking for their presence in our code. If you have other ways to deal with this kind of thing, please let me know!