Vue 3 / Nuxt 3 作用域槽,具有从 props 推断出的通用数据类型

Gio*_*ung 10 typescript vue.js nuxt.js vuejs3 nuxtjs3

我想在 Nuxt v3 中实现一个轮播组件。该组件接收一系列项目。该组件仅实现逻辑,而不实现样式或结构。

现在这是我的组件:

components/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>
Run Code Online (Sandbox Code Playgroud)

这里轮播的逻辑并不重要。

在父组件中,我可以像这样使用该组件:

<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>
Run Code Online (Sandbox Code Playgroud)

这很好用。除此之外我想要的是打字。title和的类型description当然是任意的,因为在道具中,carousel.vue项目的类型是unknown[]

我发现这篇文章展示了如何制作通用组件,但我不想要这个,因为我不得不弄乱 nuxt 的自动导入系统。

如何从carousel.vue道具中的给定项目实现类型推断?

Mat*_*ser 5

更新:2023 年 5 月

从 Vue 3.3 开始,正式支持通用组件。

您需要定义一个通用参数。修改您的carousel.vue组件以使用标记generic中的属性<script setup>,并将其转换为使用基于类型的方法,defineProps以便它能够正确地获取泛型。

<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>
Run Code Online (Sandbox Code Playgroud)

现在,插槽上的道具将根据物品的类型正确推断。

这里我传递了一个带有 id 的对象数组,每个对象都是字符串类型

它正确推断了 {id} 的类型

2023 年 5 月之前

在早期版本的 VSCode/Volar 中,您需要启用实验性标志。它需要启用experimentalRfc436tsconfig.json 下的选项vueCompilerOptions

// tsconfig.json
{
  // ...
  "vueCompilerOptions": {
    "experimentalRfc436": true
  }
}
Run Code Online (Sandbox Code Playgroud)

这不再是必要的,因为它在最新版本的 Volar 中默认启用。