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,
    },
  },
};

(I've previously written about how to use the validator pattern and other tricks with prop types.)

What a pain.

And when the prop types of the Icon component are updated, you can be sure that you'll forget to come back 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 "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.toUpperCase()}`] = val;
});

export default {
  components: { Icon },
  props: {
    ...iconProps,
    heading: {
      type: String,
      required: true,
    },
  },
};

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