1

Wrapper component

<script setup lang="ts">
import InputBase,{ Props as InputBaseProps } from "./InputBase.vue";


interface Props extends InputBaseProps {
  label?: string;
  labelClassName?: string;
...other props
}
const props = defineProps<Props>();
</script>

<template>
  // Wrapper specific stuff that uses the above props
<InputBase v-bind="$attrs"  />
</template>

Wrapped component

<script setup lang="ts">
import InputBase,{ Props as InputBaseProps } from "./InputBase.vue";


export interface Props {
  name:string;
...other props
}
const props = defineProps<Props>();
</script>

<template>
  // InputBase logic

</template>

I want to extract just Wrapper Props out and use it in the wrapper and pass everything down to the base component. How could I go about implementing this so that I get all the prop types in the wrapper but I can still easily extract out the InputBaseProps and give it to the base.

I could do this by removing the extends but then the wrapper looses ts intellisense of the base components props. I've tried destructuring with toRefs but that cause issues.

1
  • stackoverflow.com/staging-ground/78997944 - the comments weren't moved here. "But the issue is when I do this the InputBaseProps gets removed from attrs making it difficult for me to separate out the wrapper props and the InputBaseProps. If this was react I ouwld destructor the props as const {label,labelClassName,...inputProps} = props; and then directly pass inputProps to Input component but I can't destructor states in vue" - yes, this is the right direction, adjusted for vue reactivity. This destructuring happens in React on every render and you need to guarantee the same in Vue Commented Sep 19 at 8:23

1 Answer 1

0

It's not practical to keep using attrs at this point, they are a simple way to pass the whole set, including event listeners. If this is not the case, props can be transformed in the required way with reactivity API.

If label and labelClassName need to be used in wrapper component, and the rest need to be passed as is to wrapped component, the respected props objects need to be computed from props, which is readonly reactive object. Destructuring or any type-aware pick and omit helper implementations can be used for this:

const wrapperProps = computed(() => {
  const { label, labelClassName } = props;
  return { label, labelClassName };
});


const wrappedProps = computed(() => {
  const { label: _label, labelClassName: _labelClassName, ...rest } = props;
  return rest;
});

Since props is correctly typed, the types of computed props are supposed to be inferred.

3
  • Thanks this worked. Could explain why computed is required? Also I have a similar issue with event listeners too. The InputBase has couple of comp events. I want to pass the listeners from the wrapper to the InputBase. Commented Sep 19 at 9:38
  • Because wrapperProps, etc needs to be updated on changes in "props", this is achieved with vue reactivity, i.e. either computed or a watcher. As for the events, that's something the question should've mention as this affects a possible answer. For event handlers passthrough render function would work because events are translated to on* props/attrs similarly to React, but I didn't check how well it works with TS, I suspect it doesn't. For a limited set of events it makes sense to just pass them through explicitly like <InputBase v-bind="wrappedProps" @foo="emit('foo', $event) /> Commented Sep 19 at 10:37
  • Where emit could be strongly typed with defineEmits Commented Sep 19 at 10:39

Not the answer you're looking for? Browse other questions tagged or ask your own question.