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>
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