Vue 3/Nuxt 3 scoped slots with generic data types inferred from props
P粉863295057
P粉863295057 2023-11-02 21:59:05
0
1
779

I want to implement a carousel component in Nuxt v3. This component receives a list of items. This component only implements logic, not style or structure.

Now this is my component:

Component/tdx/carousel.vue

<template>
  <div>
    <slot name="last"></slot>
    <div v-for="item in items">
      <slot
        name="item"
        v-bind="item"
      ></slot>
    </div>
    <slot name="next"></slot>
  </div>
</template>

<script setup lang="ts">
const props = defineProps({
  items: {
    type: [],
    required: true,
  },
  spotlight: {
    type: Number,
    default: 1,
    validator(value: number) {
      return value > 0;
    },
  },
});
</script>

The logic of the carousel is not important here.

In the parent component I can use the component like this:

<template>
  <div class="container">
    <TdxCarousel :items="exampleArray">
      <template #item="{ title, description }">
        <p class="font-semibold text-2xl">{{ title }}</p>
        <hr />
        <p>{{ description }}</p>
      </template>
    </TdxCarousel>
  </div>
</template>

<script setup lang="ts">
const exampleArray = ref([
  {
    title: 'Item 1',
    description: 'Desc of item 1',
  },
  {
    title: 'Item 2',
    description: 'Desc of item 2',
  },
]);
</script>

This works great. Other than that what I want is typing. The type of title and description is of course any, because in the props of carousel.vue, the type of the item is unknown[].

I found this article showing how to make a generic component, but I don't want this because I have to mess with nuxt's auto-import system.

How to implement type inference from a given item in a carousel.vue property?

P粉863295057
P粉863295057

reply all(1)
P粉476547076

Updated: May 2023

Starting from Vue 3.3, officially supports common components.

You need to define a common parameter. Modify the carousel.vue component to use the generic tag and convert it to use type-based defineProps method so that it gets the generics correctly.

<script setup lang="ts" generic="T extends any">
withDefaults(
  defineProps<{ items: T[]; spotlight?: number }>(), {
  spotlight: 1,
});
</script>
<template>
  <div>
    <slot name="last"></slot>
    <div v-for="item in items">
      <slot
        name="item"
        v-bind="item">
      </slot>
    </div>
    <slot name="next"></slot>
  </div>
</template>

Props on slots will now be correctly inferred based on item type.

Before May 2023

In earlier versions of VSCode/Volar, you needed to enable the Experimental flag. It requires the experimentalRfc436 option of tsconfig.json to be enabled under vueCompilerOptions.

// tsconfig.json
{
  // ...
  "vueCompilerOptions": {
    "experimentalRfc436": true
  }
}

This is no longer necessary as it is enabled by default in recent versions of Volar.

Latest Downloads
More>
Web Effects
Website Source Code
Website Materials
Front End Template