Why can component names in Vue only be shadowed by non-default exports?

I have a simple App, that only renders my TestComp. In the setup context of App.vue, there is also a ref called testComp. Even though I am not using the recommended Template Expression of <TestComp /> (and instead <test-comp />), everything renders fine.

<!-- App.vue -->

<script setup>
import { ref } from 'vue'
import TestComp from './TestComp.vue'

const testComp = ref(null)

</script>

<template>
  <div>
    <test-comp />
    <!-- Recommended is <TestComp />, and this avoids the issue, but not the focus here -->
  </div>
</template>
<!-- TestComp.vue -->
<script setup>

</script>
<template>
  <div>
    I am a test component.
  </div>
</template>
// components.ts
import TestComp from './TestComp.vue'
// supposed to group multiple component definitions together
export {
  TestComp
}

Vue SFC Playground

So the Template Expression <test-comp /> is evaluated as the imported component TestComp and not my variable testComp.

Instead of importing TestComp directly, we can use a file that is grouping my component definitions by importing and re-exporting them in an object. We can achieve that by replacing the import:

from: import TestComp from './TestComp.vue'

to: import { TestComp } from './components.ts'.

Now the Template Expression <test-comp /> seems to be evaluated to the ref testComp, and I get a warning: [Vue warn]: Invalid vnode type when creating vnode: null – the component is not rendered.


Why is there a difference between TestComp being imported directly, and being part of another files non-default export?