2

I have a tab component in a vue 3 (3.5.12) typescript project. The tabs accept a prop called nav which might look something like this:

const nav = ref([
        {
            id: 'about',
            name: 'About',
        },
        {
            id: 'enquire',
            name: 'Enquire',
        },
    ])

For each of the nav items, we generate a slot with a simple sequential naming system for the content.

<div v-if="nav" class="tabs-content">
    <div
        v-for="(tab, index) in nav"
        :id="tab.id"
        :key="index"
        <slot :name="`tab${index + 1}`"></slot>
    </div>
</div>

giving us tab1 and tab2 slots. which means we can populate the tab content like so:

<template #tab1></template>

However when running the build command, vue-tsc throws the error:

error TS2339: Property 'tab1' does not exist on type 'TabsSlots'.

The vue docs have a section on this, but its not very in-depth: https://vuejs.org/api/sfc-script-setup.html#defineslots and all of my attempts with this have been unsuccessful.

I have ensured typescript, vue, vue-tsc packages are all up to date

All of my approaches so far were an attempt to register the dynamic slots based on the nav prop, the same way that the slots themselves are created.

Does anyone have a solution to this? I cannot find anything for this specific issue on StackOverflow and AI tools seem to be struggling with defineSlots being a newer feature.

See Vue SFC Playground Demo here

4
  • tab:${index + 1} means the tab name is actually something like tab:1 and not tab1 Commented Nov 13, 2024 at 17:58
  • thanks @yoduh yeah thats a typo. updated the snippet Commented Nov 13, 2024 at 18:27
  • could you prepare a snippet on vue sfc playground? Commented Nov 13, 2024 at 21:53
  • sure @AlexanderNenashev - link to it added to the post Commented Nov 13, 2024 at 22:39

2 Answers 2

0

Try a generic Tab[] type and use it for the props and slots. Don't forget to add as const to nav:

Playground

<script lang="ts" setup generic="Tabs extends Readonly<Tab[]>">
  import { ref } from 'vue'

  export interface Tab {
        id: string
        name: string
    }

  const selected = ref('about')
  
  const $slots = defineSlots<{
        [K in Exclude<Exclude<keyof Tabs | `${Tabs['length']}`, keyof []>, '0'> as `tab${K & string}`]: () => void
    }>();
    
  const props = withDefaults(
        defineProps<{
            nav?: Tabs
        }>(),
        {
            nav: undefined,
        }
    )
</script>

Intellisense works: enter image description here

Sign up to request clarification or add additional context in comments.

3 Comments

Thanks Alexander, but this didn't work for me im afraid. Weirdly in my local environment, intellisense doesnt even recognise them like they do in playground. The build errors still occur and new ones that also show up in playground are also reported: Property 'id' does not exist on type....
@dstaffcs i would suggest to upgrade ts, vue-tsc and vue
these are already up to date
0

I can't believe I am writing this but... it was because the component is called "tabs". I changed it to "AppTabs" and intellisense immediately accepted the dynamic slots and the errors no longer appeared in vue-tsc.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.