Search code examples
typescriptvue.jsvue-component

In Vue3 - Inferr a type to a slotProp from the modelValue


I have simplified the component I am trying to create:

// MyComp.vue

<script setup lang="ts">
import { PropType, defineProps, defineEmits } from 'vue';

const props = defineProps({
    modelValue: {
        type: Array as PropType<unknown[]>,
        required: true,
    },
});

const emit = defineEmits({
    updateModelValue: (value: unknown[]) => true,
});
</script>

<template>
    <div v-for="(item, index) in modelValue" :key="index">
        <slot :item="item" :index="index"></slot>
    </div>
</template>
// Parent.vue

<script setup lang="ts">
import { ref } from 'vue'
import { MyComp } from '.';

const myArray = ref([
    {
        name: 'A',
        id: 1,
    },
    {
        name: 'B',
        id: 2,
    },
]);

</script>

<template>
    <div>
        <MyComp v-model="myArray">
            <template #default="{ item }">
                <!-- item is of type unknown - type not inferred :( -->
                <div>{{ item }} </div>
            </template>
        </MyComp >
    </div>
</template>

My problem is that the type of item does not get inferred, so I do not get the intelliSense I want.

How can I achieve this ?

(StackOverflow would not let me post this question without more details, so I added this sentence)


Solution

  • Looks like you have literally set your array item type to unknown. I don't think there is anything left for TS to infer at that point.

    If you are using Vue version 3.3 or above, you can use generic components:

    // MyComp.vue
    
    <script setup lang="ts" generic="T">
    import { PropType } from 'vue';
    
    const props = defineProps({
        modelValue: {
            type: Array as PropType<T[]>,
            required: true,
        },
    });
    
    const emit = defineEmits({
        updateModelValue: (value: T[]) => true,
    });
    </script>
    

    This will infer types correctly, see playground