Estus Flask
Estus Flask

Reputation: 223104

Prop types in Vue wrapper component

There is properly typed BaseComp base component, which can be a third-party component and so can't be rewritten to suit our needs:

<script lang="ts">
...
export default defineComponent({
  name: 'BaseComp',

  props: {
    baseProp: {
      type: String,
    },
    anotherBaseProp: {
      type: String,
    },
  },
  ...
});
</script>

And MyComp wrapper component:

<template>
  <BaseComp
    v-bind="$attrs"
    :base-prop="myBaseProp"
    :another-base-prop="someProp"
  />
</template>

<script lang="ts">
...
export default defineComponent({
  name: 'MyComp',

  components: { BaseComp },

  props: {
    baseProp: {
      type: String,
    },
    someProp: {
      type: String,
    },
  },

  setup(props) {
    const myBaseProp = computed(() => transform(props.baseProp));

    return { myBaseProp };
  },
});
</script>

MyComp is expected to have the same prop types as BaseComp in TypeScript, plus someProp - both internally (props inside setup function) and externally (templates and render functions).

The use of $attrs works as it should at runtime but MyComp won't get unlisted prop types from BaseComp at compilation time (anotherBaseProp).

MyComp doesn't use extends as it doesn't inherit all component options, just props.

What is the proper way to make MyComp expose the correct props?

Can it allow to not list common props a wrapper that it explicitly uses (someProp)?

Upvotes: 1

Views: 2060

Answers (1)

Kapcash
Kapcash

Reputation: 6919

In Vue3, you have two ways to do this: with mixins or composition api. The composition api being the recommended way to do as stated in the Vue 3 documentation.

Officially, you can't extends only some parts of another components without extending it entirely.

Inherit from a external component (no access to source code)

EDIT: There is a solution that is not documentation and may be breakpoint for various reasons.

If possible, I do not recommend to use this method unless it has been officially documented somehow.

import BaseComp from 'BaseComp.vue'

export default defineComponent({
  name: 'MyComp',
  components: { BaseComp },
  props: {
    ...BaseComp.props, // Object containing BaseComp props object
  },
});

EDIT: You have access to the parent component's code

With composition api

Export a function with the common props definition.

export const useGlobalProps = () => {
  return {
    baseProp: {
      type: String,
    },
    someProp: {
      type: String,
    },
  },
}

with defineComponent method

import { useGlobalProps } from 'globalProps'

export default defineComponent({
  name: 'BaseComp',
  props: {
    ...useGlobalProps(),
    otherProp: Boolean,
  }
  ...
});

or script setup model

<script setup>
import { useGlobalProps } from 'globalProps'

defineProps({
  ...useGlobalProps(),
  otherProps: Boolean,
})
</script>

With mixins

// base-mixin.js
export default {
  props: {
    baseProp: {
      type: String,
    },
    someProp: {
      type: String,
    },
  },
}
import BaseMixin from 'base-mixin'

export default defineComponent({
  name: 'BaseComp',
  mixins: [BaseMixin],
  ...
});

export default defineComponent({
  name: 'MyComp',
  mixins: [BaseMixin],
  ...
});

Upvotes: 1

Related Questions