Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to correctly circular reference components in Vue 3 with Typescript?

I have two Vue components. For simplicity of this question I called them component A and component B.

Component A

<template>
    <div>{{ recursive.text }} component A</div>
    <component-b v-if="recursive.value" :recursive="recursive.value" />
</template>

<script lang="ts">
    import { defineAsyncComponent, defineComponent } from 'vue';
    export default defineComponent({
        name: 'ComponentA',
        components: {
            ComponentB: defineAsyncComponent(() => import('./B.vue')),
        },
    });
</script>

<script lang="ts" setup>
    interface RecursiveProp {
        text: string;
        value?: RecursiveProp;
    }

    const props = defineProps<{ recursive: RecursiveProp }>();
</script>

Component B

<template>
    <div>{{ recursive.text }} component B</div>
    <component-a v-if="recursive.value" :recursive="recursive.value" />
</template>

<script lang="ts">
    import { defineAsyncComponent, defineComponent } from 'vue';

    export default defineComponent({
        name: 'ComponentB',
        components: {
            ComponentA: defineAsyncComponent(() => import('./A.vue')),
        },
    });
</script>

<script lang="ts" setup>
    interface RecursiveProp {
        text: string;
        value?: RecursiveProp;
    }

    const props = defineProps<{ recursive: RecursiveProp }>();
</script>

For example, when I import Component A into another component and pass it the correct props, the code works with no errors showing in the browser. Component A and Component B recursively render the specified amount of times based on the given prop. But for some reason Visual Studio Code complains when the components reference to each other in this way. I attached a picture of the error below. This error is present in both component A and component B.

enter image description here

In the Vue documentation, this problem is referenced inside the Handling Edge Cases section. The only problem is that it is Vue 2 documentation: https://v2.vuejs.org/v2/guide/components-edge-cases.html#Circular-References-Between-Components

In Vue 3 you can use defineAsyncComponent. This makes my code work, but makes the error appear in Visual Studio code: https://vuejs.org/guide/components/async.html#async-components=

I am aware I can globally register one of the components. But that is something I want to avoid.

Is there a way to correctly circular reference components in Vue 3 with Typescript?

like image 711
Errol59 Avatar asked Sep 11 '25 22:09

Errol59


1 Answers

It seems this issue only affects <script lang="ts"> and is unrelated to the IDE or the <script setup lang="ts">.

A workaround is to register the recursive async components in <script setup lang="ts"> instead of <script lang="ts">:

<!-- A.vue -->
<template>
    <div>{{ recursive.text }} component A</div>
    <component-b v-if="recursive.value" :recursive="recursive.value" />
</template>

<script lang="ts" setup>
import { defineAsyncComponent } from 'vue'
           👇
const ComponentB = defineAsyncComponent(() => import('./B.vue')) 

interface RecursiveProp {
    text: string;
    value?: RecursiveProp;
}

const props = defineProps<{ recursive: RecursiveProp }>();
</script>
<!-- B.vue -->
<template>
    <div>{{ rec.text }} component B</div>
    <component-a v-if="rec.value" :recursive="rec.value" />
</template>

<script lang="ts" setup>
import { defineAsyncComponent, computed } from 'vue'
         👇
const ComponentA = defineAsyncComponent(() => import('./A.vue'))

interface RecursiveProp {
    text: string;
    value?: RecursiveProp;
}

const props = defineProps<{ recursive: RecursiveProp }>();

// compute stop-condition for the recursion
const rec = computed(() => ({
    ...props.recursive,
    value: undefined
} as RecursiveProp))
</script>

demo

like image 104
tony19 Avatar answered Sep 13 '25 12:09

tony19