The approach I took worked in VS Code + Volar 0.40.13 and it also works with Volar 1.0.0. (ensure you update your tsconfig.json file to include "vueCompilerOptions.jsxTemplates": true
)
You first define the "non-generic" Vue component using a "non-generic" version of your type.
// MySelectBase.vue
type SelectOptionBase = {
id: string | number;
text: string;
[key: string]: unknown;
}
defineProps<{
options: SelectOptionBase[];
modelValue: SelectOptionBase;
}>()
defineEmits<{
(e: 'update:modelValue', v: SelectOptionBase): void
}>()
Then define the "Generic" version of the component.
<script lang="ts">
import MySelectBase from "./MySelectBase.vue";
export type SelectOption<T = {}> = {
id: string | number
text: string
} & T;
interface Props<T> {
options: SelectOption<T>[];
modelValue: SelectOption<T>;
}
type MySelect = new <T = {}>(props: Props<T>) => {
$props: Props<T>;
$emit: {
(e: "update:modelValue", v: SelectOption<T>): void;
};
};
export default MySelectBase as MySelect;
</script>
You can then use the MySelect
component
<script setup lang="ts">
import { ref } from "vue";
import MySelect from "./MySelect.vue";
const item = ref<SelectOption<{ name: string; }>>();
const items = ref<SelectOption<{ name: string; }[]>>([
{ id: 1, text: "Johnny", name: "John" },
{ id: 2, text: "MJ", name: "Mary-Jane" },
]);
</script>
<template>
<MySelect v-model="item" :options="items" />
</template>
When you hover over the options
prop it should show MySelect<{...}>.options: { id: number, text: string; name: string }