-
-
Notifications
You must be signed in to change notification settings - Fork 481
Closed as not planned
Closed as not planned
Copy link
Labels
questionFurther information is requestedFurther information is requested
Description
Volar does not narrow v-model type with discriminated union props in SFC
Summary
Volar/Language Tools fails to narrow v-model
type in <script setup>
when component props use a discriminated union. The code runs, but IDE type analysis reports incorrect component/slot types and v-model
type is not narrowed based on the discriminator.
Expected
- With a discriminated union on props (e.g.,
onlyId: true
vsonlyId?: false
), IDE should narrowmodelValue
type accordingly, anduseVModel
/v-model
should reflect that type in both template and parent usage.
Actual
- Narrowing is lost: IDE treats
modelValue
/v-model
as the wide union and misreports types in template/slots. Runtime is fine.
Minimal Reproduction (SFC)
<script setup lang="ts">
import { useVModel } from "@vueuse/core"
import type { Ref } from "vue"
type Client = { id: number; full_name: string }
type BaseProps = {
label?: string
}
type PropsWithOnlyId = BaseProps & {
onlyId: true
modelValue?: number | null
}
type PropsWithoutOnlyId = BaseProps & {
onlyId?: false
modelValue?: Client | number | null
}
type ComponentProps = PropsWithOnlyId | PropsWithoutOnlyId
const props = defineProps<ComponentProps>()
const emit = defineEmits<{ "update:modelValue": [value: Client | number | null] }>()
// Inference-friendly usage (no generics):
const model = useVModel(props, "modelValue", emit)
// Expected: if props.onlyId === true => model: Ref<number | null>
// Actual: IDE treats model as Ref<Client | number | null> (no narrowing)
</script>
<template>
<input v-model="model" />
<!-- Expected: narrowed to number|null when onlyId is true -->
</template>
Notes
- If we remove the discriminated union (single props type), IDE behaves but we lose correctness.
- If we force generics on
useVModel
, we hit generic constraints differences across VueUse versions and it regresses in IDE. The most stable is relying on inference, but narrowing still fails.
Versions
- Vue: 3.5.18
- TypeScript: 5.8.3
- vue-tsc: 3.0.1
- @vueuse/core: 13.4.0
- Node: 22.17.0
- Volar / language-tools: latest (observed with VS Code + Vue extension)
Repository / Context
- Real-world component where it reproduces (simplified):
frontend/apps/company/src/entities/client/ui/client-select/ClientSelect.vue
What would help
- Either improved narrowing for discriminated unions in
defineProps
+useVModel
paths, or guidance/workaround to keep IDE narrowing without sacrificing runtime ergonomics.
Related
Thanks!
Metadata
Metadata
Assignees
Labels
questionFurther information is requestedFurther information is requested