Stealing Prop Types

Often I find that I'm copying prop types from a child component just to use them in a parent component. But I've discovered that stealing those prop types is much better than just copying them.

For example, we have an Icon component being used in this component:

<template>
<div>
<h2>{{ heading }}</h2>
<Icon
:type="iconType"
:size="iconSize"
:colour="iconColour"
/>
</div>
</template>

To get this to work, we need to add the correct prop types, copying from the Icon component:

import Icon from './Icon';
export default {
components: { Icon },
props: {
iconType: {
type: String,
required: true,
},
iconSize: {
type: String,
default: 'medium',
validator: size => [
'small',
'medium',
'large',
'x-large'
].includes(size),
},
iconColour: {
type: String,
default: 'black',
},
heading: {
type: String,
required: true,
},
},
};

What a pain.

And when the prop types of the Icon component are updated, you can be sure that you'll forget to return to this component and update them. Over time bugs will be introduced as the prop types for this component start to drift away from the prop types in the Icon component.

So that's why we'll steal them instead:

import Icon from './Icon';
export default {
components: { Icon },
props: {
...Icon.props,
heading: {
type: String,
required: true,
},
},
};

It doesn't have to get any more complicated than that!

Except in our example, we have an "icon" added to the beginning of each prop name. So we'll have to do some extra work to get that to happen:

import Icon from './Icon';
const iconProps = {};
// Do some processing beforehand
Object.entries(Icon.props).forEach((key, val) => {
iconProps[`icon${key[0].toUpperCase()}${key.substring(1)}`] = val;
});
export default {
components: { Icon },
props: {
...iconProps,
heading: {
type: String,
required: true,
},
},
};

If the prop types in the Icon component are modified, our component will stay up-to-date.

But what if a prop type is added or removed from the Icon component? We can use v-bind and a computed prop to keep things dynamic and cover those cases.