Home > other >  Recursive usage of slots in vue3/typescript/sfc
Recursive usage of slots in vue3/typescript/sfc

Time:08-21

I'm trying to implement simple treeview using vue3 and typescript

npm init vue@latest // when asks about typescript support - say yes, and just press Enter on all other questions
cd '.\vue-project\'

add file TreeNode.vue

<template>
  <div>
    <div>
      <slot :item="item" />
    </div>
    <div style="margin-left: 10px" v-for="(child, index) in item.children" :key="index">
      <TreeNode :item="child">
        <template v-slot="{item}">
          <slot :item="item" />
        </template>
      </TreeNode>
    </div>
  </div>
</template>

<script setup lang="ts">  
  const props = defineProps<{ item: Item }>()
</script>

<script lang="ts">
  export type Item = {
    name: string
    children: Array<Item>
  }
</script>

when run npm run type-check

and got error:

src/components/TreeNode.vue:8:19 - error TS2615: Type of property 'default' circularly references itself in mapped type '{ [K in keyof (Readonly<InternalSlots> & { default: (_: any) => any; })]-?: (Readonly<InternalSlots> & { default: (_: any) => any; })[K] extends ((obj: infer O) => any) | undefined ? O : any; }'.

8         <template v-slot="{item}">

Any idea how to avoid this error ??

CodePudding user response:

No need to two slots the second one is enough without using default slot template, In the first slot you should render the content of the current node

<script setup lang="ts">
defineProps<{ item: Item }>()
</script>

<script lang="ts">
interface Item {
  name: string
  children: Array<Item>
}
</script>

<template>
  <div>
    <div>
      {{ item.name }}
    </div>
    <div v-for="(child, index) in item.children" :key="index" style="margin-left: 10px">
      <TreeNode :item="child">
        <slot :item="item" />
      </TreeNode>
    </div>
  </div>
</template>

LIVE DEMO

CodePudding user response:

As I said in the comments, you code works perfectly fine (it renders). Error is from TS. My guess is it's some minor typing problem in Vue (or maybe a limitation of TS)

I was able to get rid of the problem using dynamic slot names - more dynamic code makes it impossible to statically analyze the types, so TS stops complaining

TreeNode.vue

<script setup lang="ts">
const props = defineProps<{ item: Item }>();
</script>

<script lang="ts">
export type Item = {
  name: string;
  children?: Array<Item>;
};

const slotName = 'default';
</script>

<template>
  <div>
    <div>
      <slot :item="props.item" />
    </div>
    <div
      v-for="(child, index) in props.item.children"
      :key="index"
      style="margin-left: 10px"
    >
      <TreeNode :item="child">
        <template #[slotName]="{ item }: { item: Item }">
          <slot :item="item" />
        </template>
      </TreeNode>
    </div>
  </div>
</template>

Demo - just open another terminal and run npm run check

  • Related