defineModel ignores TS types
Vue version
3.3.8
Link to minimal reproduction
Steps to reproduce
Create a Component with a defineModel that got multiple types
<script setup lang="ts">
const modelValue = defineModel<string | number | null | boolean>()
</script>
<template>
<input type="text" v-model="modelValue">
</template>
Use the component.
<script setup lang="ts">
import { ref } from 'vue'
import Comp from "./Comp.vue"
const msg = ref('Hello World!')
</script>
<template>
<h1>{{ msg }}</h1>
<Comp v-model="msg" />
</template>
Observe warning:
What is expected?
Expected is that the component accepts the string without any errors.
What is actually happening?
The component throws a warning that it got passed a String instead a Boolean
System Info
No response
Any additional comments?
Im now defineModel is an experimental feature , but i guess the user would expect that it works as the usual prop type definition that throws no warning.
I think this is related to special handling for boolean props that we also have in other scenarios.
When we define props with a type interface, we generate the prop runtime definition without a runtime type (because the component will provide TS types to devs):
const modelValue = defineModel<string | number | null>()
// results in runtime prop def:
props: {
"modelValue": {},
},
But when the prop is of type Boolean, we need to know that during runtime for casting props values properly.
const modelValue = defineModel<boolean>()
// results in runtime prop def:
props: {
"modelValue": { type: Boolean },
},
Problem is that we get the same result for a union type containing boolean
like in the repro:
const modelValue = defineModel<string | number | null | boolean>()
// results in runtime prop def:
props: {
"modelValue": { type: Boolean },
},
It would need to be:
const modelValue = defineModel<string | number | null | boolean>()
// results in runtime prop def:
props: {
"modelValue": { type: [Boolean, String, Number] },
},
I briefly reviewed the source code and it looks like it was intentionally done. In the product environment, supports Boolean and Function when options are passed in. https://github.com/vuejs/core/blob/fc7902982a4bc9f0c9cdb0c9c222bc43a9d5c458/packages/compiler-sfc/src/script/defineModel.ts#L123-L128
@RicardoErii
This logic is incorrect. No filtering is required if there is a Boolean
or Function
.
https://github.com/vuejs/core/blob/fc7902982a4bc9f0c9cdb0c9c222bc43a9d5c458/packages/compiler-sfc/src/script/defineProps.ts#L262-L276